Welcome to the documentation of the project of PHYS291, spring 2011. The project consists of two tasks, which both are centered around data analysis and the use of ROOT.
Task: We are working with ESD (Event summary data) files from last years proton-proton collision in LHC. This data is organized in a ROOT tree, with several branches. The only branch going to be used in this project is “Tracks”, which holds AliESDtrack objects. There are two trees; the esdTree, which holds the data from the offline analysis, and the HLTesdTree, which holds the data from the high level trigger(HLT) analysis.
In the first task we are supposed to access the trees, and plot distributions of the following quantities from both the trees in the same histogram:
-theta angle of the collision
-phi angle of the collision
-time projection chamber clusters per track
-charged track multiplicity per event
Implementation: The source code of this task can be found here.
What the code does, step by step, is the following:
Create histograms. To avoid problems mentioned in the comments below, manually set the maximum range of the y-axis for some of the histograms.
The next step is to extract the data and fill them into the created histograms. To do this, I start by creating two chains, which are basically lists of .root files containing the same trees. The trees in this case are the ones containing the offline and HLT data. We can now access the branches of these trees. I declare pointers to variables holding AliESDEvent and AliESDtrack objects. By using the function AliESDEvent::ReadFromTree(TTree *tree) and Tchain::GetEntry(Int_t entry), we can read the data from the chains into the variables pointed to by the pointers. And by using AliESDEvent::GetTrack(Int_t track), we can read the tracks into the variables. We need to do this for each event and every track in the event, so a for loop is created. I now use member functions to extract the data from the events and tracks, and fill them into the histograms in the loop.
Now that the histograms are created and filled, the only thing remaining is to display and save them. The next part of the code displays a menu with the available plots, and lets the user type in which plot that is to be displayed. The user has to pick a number associated with a specific plot from the menu. If the choice is invalid, a loop is entered, asking the user to try again. The user stays inside the loop until a valid choice is typed in.
Comments on the source code: this code asks the user which plot shall be displayed and saves this plot as a .png file. I chose this format, because it takes the least amount of space and is well suited for pictures with large areas of the same color, which is the case with histograms. I chose the color blue and red for the two plots, since with the default color, black, the line tends to be hidden by the black axes. It might not be clear why the names of the histograms are a parameter in the function that draws them. This is simply because it is needed to make the legend associate the lines of the plot with the right color. You can see that the name of the histograms is used in the function TLegend::AddEntry(...).
I encountered a problem when plotting the data of the two trees in the same histogram; the axes of the histogram drawn first is kept. This can cause problems if the data of the second histogram is not well represented by the range of the axes of the first. I solved this problem by manually setting the maximum range of the y-axis, since this is the one that causes problems. This is the least general way to do it, since does not adjust itself if the data were to be different, but it is also the simplest.
Also, I have not bundled much of the code into functions. This is in order to avoid the problems of scopes of objects, in particular histograms. Once again, this might not be the best way to do it, but it simplifies things when writing the code.
Expectations on the results: I expect the momentum to be distributed in the same manner as the momenta in an ideal gas, so I think the momentum distribution will resemble a Maxwell curve. Also, if a large proportion of the momenta is perpendicular on the beam pipe, I expect the transverse momentum to share the same features as the total momentum. This can be investigated by studying the theta angle. If this shows a peak at π/2, I expect the total momentum and the transverse momentum to share the same features. However, I do not know how to further predict the shape of the distribution of the theta angle. The phi angle, however, I expect to be approximately uniform, since I do not see why one azimuthal angle should be preferred over another. The phi angle denotes the azimuthal angle. Also, I do not know how to predict the shape of TPC cluster per track or charged track multiplicity per event. The only feature I can predict with these, is that they will have to go to zero at large values.
The results of the first task is presented here.
Potential improvements of the code: First of all, the source code could be made prettier if more of the code was bundled into functions. It would also make it more flexible; if one wanted to change anything, one only has to make the one change in the function. The main weakness of the code is namely that it is not very flexible. If another data set was chosen, some of the histograms would not adjust to this change. It is a code written specifically for the data that was used in the running of the code, and this is not a good thing. The directory of the data used to fill the histograms is also set in the source code.
Task: The AliESDtrack class has a member function called GetMass(); which can be used for particle identification (PID). In this task, we are going to calculate the invariant mass of proton(p) + π- and π+ + π- systems. These are the typical decay products of Λ and K0, respectively. To find these plots, we calculate the invariant mass of all possible combinations of these particles that belong to the same track. This introduces a background error of uncorrelated pairs of particles, that is particles that do not come from the same decay. To estimate this error, we will use a technique called event mixing. Here we calculate the invariant mass of pairs of particles belonging to different events, so we are sure that they are not correlated. This will give us an idea of the background error of the first calcualation.
Implementation: The source code of this task can be found here.
What the code does, again step by step, is the following:
This code uses the class called TLorentzVector to make the calculations with invariant mass easier. It starts by defining these, creating the histograms that will represent the data and creates a chain with the offline esdTree.
Next, it loops through the events to find the protons in a track. To do this, I use the GetMass() function and plot the distribution of the masses of the tracks in all events. In this plot, we can see the pions and protons that are needed for the calculations. To do this calculation, I loop through all events and extract out those that have the mass of the proton. I then calculate the invariant mass of the system consisting of this proton and all other π- belonging to the same event. This is done with all protons in all events in the first for-loop, and for all the π+ + π- systems in the next loop. The results are filled into the created histograms. We expect to see peaks from the decay of Λ and K0.
The next step is to estimate the background of uncorrelated tracks with the event mixing technique. This is done in a quite simple manner. For the proton system, event 9 is looped over. I chose event 9, because I know that this event has proton tracks. To be sure that protons are found in this event “Proton found in event 9!” is printed when the variables are set. The whole event is looped over, and the variables are set in each loop, so consequently the proton chosen for the calculation of the background is the last proton of the event. The invariant mass of this proton and pions from all other events than event 9 is calculated. This invariant mass is filled into a histogram. The same is done for the π+, only this time event 13 is chosen, since I know that this event has at least one π+-track.
Now we have filled the histograms representing the invariant mass of the two systems as well as the background estimation. The next step is to subtract the estimated background from the invariant mass spectra. We cannot do this with the histograms as they stand now, because the number of entries they contain are not in proportion to each other, so they are not comparable. To make them comparable, we must scale them with a factor that is proportional to the bin contents of both histograms. This is done by normalization, and both histograms are normalized away from where the signal from the decayed particle is expected. So the more noise, the more the less the histogram will contribute. After the normalization, the background histogram is subtracted of the invariant mass spectra.
The menu is displayed to the user, and one can choose which plot is to be displayed. This is done in the same manner as in task 1.
This code also has a function to draw and save histograms, which is almost a copy of the function that does the same in task 1. However, this time we do not have to create legends or move statistics boxes. The last step of the code asks the user which plot that shall be displayed and the histogram is saved in the current directory.
Comments on the source code: The code is based on the identification of the different particles, where GetMass() is used. So the whole code sort of hinges on this function, since when the protons and the pions are found, one of the criteria is that they have the right mass returned by this function. This is the reason I chose the mass distribution to be one of the histograms that can be displayed. In this way, the use of the GetMass() function is justified and one can see some of the particles that are in the events. The estimation of the background is done in a simple manner, by just using one single proton and π+. This gives a crude idea of the introduced background, but could surely be done in a better way by considering more tracks. However, this introduces the problem of looping over different events inside the same loop, or nested loop. This was an aspect I found hard to solve, and I am very interested in possible solutions to this problem. Also, the range of the integration in the normalization process can be discussed. However, I am not so sure if the final result is very sensitive to these limits.
Expectations on the results: The most important result will be the peaks of Λ and K0, which I expect to see in the plots of the invariant mass. Also, in the distribution of the masses of the tracks, I expect to see sharp peaks. I also expect to see protons and pions in this plot. I do not really know what to expect from the background estimations, but I assume that the background signal will not peak at the masses of Λ and K0. If this is the case, I will draw the conclusion that it is a coincidence.
The results of the second task is presented here.
Potential improvements of the code: This code, as with the first task, could be made more general by bundling more code into functions. The code contains many loops, and the code could be made easier to read by putting these into functions and naming the function after what it does. The histograms does not suffer from the same stiffness as in task 1, as they will adjust to different data in this case. As already mentioned, the estimation of the background could also be implemented in a cleaner way.
For questions or comments, do not hesitate to send me a mail at: firstname.lastname@example.org
I want to thanks Boris Wagner for help and a nice subject, PHYS291.