ROOT is a C++ library, and as such you will be writing C++ code to do the exercises in this lab. Although C++ has somewhat of a reputation for being a complex language, this tutorial will show you some of the basic features of C++ that you'll need to know to complete the later exercises in this lab. Note that if you're already familiar with C++ then you can skip directly to Unnamed ROOT Scripts.
(Note: This tutorial dives into the details of C++ somewhat; don't stress-out about memorizing these details in one pass, but instead use it as a reference when you're trying to work on your code. Please ask questions when something doesn't make sense. Also google helps.)
C++ is an imperative object-oriented programming language. What this means is
ROOT allows us to write scripts which can be simpler than full C++ programs. Still, we need to understand the basics of C++ syntax to be able to use ROOT:
//This is a comment
There are 4 basic kinds of statements we'll use:
type variable_name;
type variable_name = value;
type variable_name(arg1,arg2,...,argN);
int x = 1;
float y = 1e3; //floats can use scientific notation
int x(1);
For fundamental types,
you can use either syntax.int* x; //could also use int *x;
Pointers simply store the address of a variable instead of
its value, and allow modifying variables that have been
passed to functions among other things.x = 3; //don't forget the semicolon
Variable assignment statements are expressions, and return the
value of the variable after being set, so that you can have
chains of variables being set like this:
x = y = z = a = b = c = 1; // now they're all 1
type function_name(type1 arg1,type2 arg2,...,typeN argN) {
//Do stuff here
return return_value;
}
An example of a function which multiplies whatever double-precision
floating point number you give it by 2 and returns it:
double times_it_by_2(double x) {
return x*2;
}
for(type var_name = initial_value; end_statement; increment) {
//Do stuff here
}
For example, to loop over the integers 1 through 10, we could do
for(int i = 1; i <= 10; i++) {
//Do stuff here. You can reference i in the loop body.
}
The ++ operator increments a variable's value by 1.
if(test1) {
// Only executes if test1 is true
}
else if(test2) {
// Only executes if test2 is true
}
... //as many else-if's as you want
else { // optional default execution
// Only executes if all previous tests were false
}
An example of using the if statement would be to ensure that a
variable only contains a non-negative value:
if(x < 0) {
x = -x;
} // we didn't need the else statement
Below is a simple unnamed script which makes use of the basic control operators of C++ already covered above:
{
for (int i=0;i<10;i++){
if(i==5){
cout << "For loop index = " << i << endl;
}
}
}
Unnamed scripts must start and end with open ({) and close (}) set braces, and contain instructions to be directly executed by the ROOT interpretor. To run the above script in ROOT:
The output of the program should be:
For loop index = 5
The best way to learn how to program is to do it, so I highly recommend modifying the script. Some ideas:
Unnamed scripts are good for simple tasks, but named scripts are much more useful for nontrivial work. Named scripts can either contain only library code, or can be executable like unnamed scripts, except with the advantage that you can supply the script with arguments.
Below is an example of a named script which draws a sine wave:
#include<TMath.h>
#include<TF1.h>
// This example shows how to have default argument values; just
// declare the argument variable with an initial value.
void draw_sine(double xlo=-TMath::Pi(), double xhi=TMath::Pi()) {
// TF1 is ROOT's function type. A TF1 can be constructed in many ways;
// check the TF1 documentation at http://root.cern.ch
TF1* sine = new TF1("sine","sin(x)",xlo,xhi);
sine->Draw();
// We don't need a return statement since return type is void
}
To run this script, you would have to save it in a file called
"draw_sine.C" and execute it in the ROOT interpreter with the
following:
.x draw_sine.C()
Note that the script must have the same name as the function in the script which should be executed (besides the file extension). This would execute the script directly, but unless the script has been compiled previously it will run in interpreter mode which is much slower than compiled mode. To compile the script, you should enter
.L draw_sine.C+
Notice the trailing plus sign; this is what causes ROOT to compile the code. To simply load the code without compiling it, omit the plus sign. Once code has been loaded with the .L command, you can simply call the functions defined in your script from the prompt; the .x command is only necessary for executing scripts which have not been loaded yet. Example:
.L draw_sine.C+
draw_sine(-5,5);
When you compile a named script, it must have any needed libraries included at the top of the file or else you'll get an error. You don't necessarily need these includes when not compiling your scripts.
A special note: We used a pointer for the function along with the new operator. Any variable which needs to exist after the function that created it has returned must be declared this way. Examples in later labs will make more use of this.
While the objective of this lab was to gain basic familiarity with ROOT, some previous students who already had experience with ROOT and C++ were able to work on an advanced program that generates random variables which follow a Gaussian distribution. We will do something similar for the next lab session by generating random variables which follow the Binomial distribution.
Below is a direct link to the write-up by Andrew Svenson that documents the program he wrote to generate Gaussian random variables:
Andrew's code is an example of shaping one distribution (the uniform distribution) to look like another (Gaussian) by throwing away some of the random data. In the next lab we will not be following the shaping approach, but will instead generate random data from a more direct approach.