Previous Next Title Page Contents

II An interactive session

In this first chapter, we will concentrate on giving the reader a feeling of the possibilities of the framework. We will use standard ROOT as well as VEGA specific examples.
The user actions will be written in bold characters.

II.1 Basic intrinsic operations

First of all, one needs to know how to exit from a program! The C interpreter has some raw commands that begin with a dot. These commands are used to do intrinsic operations, not related to any C/C++ code. The ones that you should know for the beginning are:
.q
quits the interactive session
.x
loads a macro and executes it

We will see other raw commands, as we need them, especially commands to debug scripts (step, step over, set breakpoint, etc...).

II.2 The interpreter CINT, graphical interaction through a few examples

II.2.1 First very simple example

First, go to the $ROOTSYS/tutorials and start the ROOT/VEGA interactive session:
your_prompt$ vega
The prompt that you see is "vega[]". In fact, you launched the very small vega executable, which is in $VEGA/$UNAME and which is linked with the ROOT libraries.
This program gives access via a command-line prompt to all available ROOT/VEGA classes/globals/functions. By typing C/C++ statements at the prompt, you can create objects, call functions, execute scripts, etc. For example type:

vega[] 1+sqrt(9)
(double)4.000000000000e+00

vega[] for (int i = 0; i<5; i++) printf("Hello %d\n", i)
Hello 0
Hello 1
Hello 2
Hello 3
Hello 4
vega[] .q

As you can see, if you know C or C++, you can use ROOT. No new command line or scripting language to learn.
Some comments may be made at this point. First, there is no need to put a semicolon at the end of a line. Well, you can put one if you want. This is only true for statements written on the command line. One assumes that the carriage return is enough to express the end of the line for the interpreter. This is part of the interpreter’s extensions to C++ that were made to allow an easy interaction, while not at the expense of breaking the compatibility with C/C++ language.
Some of the extensions don’t work anymore inside a macro. For example, you have to put a semicolon at the end of each line in a macro.

II.2.2 Graphical output example

Let’s try something more interesting. Again, start VEGA :

your_prompt$ vega

vega[] TF1 f1("func1", "sin(x)/x", 0, 10)
vega[] f1.Draw()

you should see something like this :
PBDada:Users:buskulic:virgoApp:vega:Documentation:VEGA_Tutorial:VEGA_UsersManual_27_05_03:VEGA_UM_27_05_0303.png

II.2.3 Classes, methods and constructors

We can stop for a second (well, a few seconds...) and explain what we have done. A more thorough introduction to C++ is given in “
More on C++(for the interested reader) ” chapter.
In ROOT and C++, we introduce the notion of object, which is just a C structure with some internal functions (called “methods”) associated to it.
The line TF1 f1("func1", "sin(x)/x", 0, 10) created an object named f1 of the type TF1 which is a one-dimensional function. The type of an object is also called a class.
In fact, the line above builds an object by giving it a set of parameters. This is one example of a function associated to a class. It is a special one since it builds an object. It is called a constructor.
To interact with an object in ROOT, the usual syntax is :
object.action(parameters)
This is the usual way of doing in C++. The dot can be replaced by -> if object is a pointer. But since the interpreter always knows the type (class) of an object, if you put a dot instead, it will be automatically replaced when necessary.
So now, we understand the two lines that allowed us to draw our function. f1.Draw() means “call the method Draw associated with the object f1 of class TF1”. We will see the advantages of using objects and classes very soon.
One point : the ROOT framework was designed as an object oriented framework. This doesn’t mean that a user cannot call plain functions. For example all the FrameLib standard functions are available in the VEGA framework.

II.2.4 ROOT related specifics

We didn’t yet explain everything about the constructor of f1 :
TF1 f1("func1", "sin(x)/x", 0, 10)
"sin(x)/x" is the function that we want to define, 0 and 10 the limits but what is "func1”? It’s the name that we give to the object f1. Most objects in ROOT have a name. That way, there are lists of objects maintained by ROOT and it’s easy to find an object by its name, especially if it is in a database. We will see why it is so when we see the notion of inheritance.

II.2.5 Graphical output example: User interaction

If you quit the framework, try to draw again the function "sin(x)/x". Now, we can look at some interactive capabilities. Every graphics drawn in a window (which is called a Canvas) is in fact a graphical object in the sense that you can grab it, resize it, change some characteristics with a mouse click. And all the changes that you do are not done on a graphical copy of the object but on the object itself. For example try to click somewhere on the x-axis and drag along this axis. You have a very simple zoom.
When the cursor is on any object, you have access to selected methods by pressing the right mouse button and obtaining a context menu showing some available methods for this object. If you try this on the function itself, you obtain this kind of behavior:
PBDada:Users:buskulic:virgoApp:vega:Documentation:VEGA_Tutorial:VEGA_UsersManual_27_05_03:VEGA_UM_27_05_0304.png
You can try for example to select the SetRange method and put -10, 10 in the dialog box fields. This is equivalent to executing the member function f1.SetRange(-10,10) from the command line prompt, followed by f1.Draw().
There are other things you may want to try. For example select the "DrawPanel" item of the popup menu. You will see a panel like this one :
PBDada:Users:buskulic:virgoApp:vega:Documentation:VEGA_Tutorial:VEGA_UsersManual_27_05_03:VEGA_UM_27_05_0305.png
Try to resize the bottom slider and click Draw. You can zoom your graph. If you click on "lego2" and "Draw", you see a 2D representation of your graph :
PBDada:Users:buskulic:virgoApp:vega:Documentation:VEGA_Tutorial:VEGA_UsersManual_27_05_03:VEGA_UM_27_05_0306.png
You can rotate interactively this 2D plot. Of course, it is possible to plot real 2D functions or graphs, not only a disguised 1D. There are numerous ways to change the graphical options/colors/fonts with the various methods available in the popup. Here are a few examples:

PBDada:Users:buskulic:virgoApp:vega:Documentation:VEGA_Tutorial:VEGA_UsersManual_27_05_03:VEGA_UM_27_05_0307.png
PBDada:Users:buskulic:virgoApp:vega:Documentation:VEGA_Tutorial:VEGA_UsersManual_27_05_03:VEGA_UM_27_05_0308.png

PBDada:Users:buskulic:virgoApp:vega:Documentation:VEGA_Tutorial:VEGA_UsersManual_27_05_03:VEGA_UM_27_05_0309.png
Line attributes
Text attributes
Fill attributes

Once the picture suits your wishes, you may want to see what are the lines of code you should put in a macro to obtain the same result. To do that, choose the "Save as canvas.C" option in the "Files" menu. This will generate a macro that you can look into to see how to set the various options. Notice that you can also save in postscript or gif formats the picture.
One other interesting possibility is to save in native root format your canvas. This will enable you to open it again and to change whatever you like, since all the objects associated to the canvas (histograms, graphs, etc...) are saved at the same time.

II.2.6 Second example : Building a multi-pad canvas

Let’s now try to build a canvas (i.e. a window) with several Pads. The pads are sub-windows that can contain other Pads or graphical objects.
vega[] can = new TCanvas("can","Test canvas",1)
vega[] can.Divide(2,2)
Once again, we called the constructor of a class, this time the class TCanvas. The difference with the previous constructor call is that we want to build an object with a pointer to it. In C, we would have used malloc() or calloc(). Here, we use the operator new, which is the equivalent in C++. Instead of free() we will use delete. Usually, one has to declare a variable before using it. Since there cannot be any ambiguity in the line above, one doesn’t need to declare a variable “can”. In case such a statement in a macro is intended to be compiled, one would obviously have to declare the variable as a TCanvas* before using it.
Next, we call the method Divide() of the TCanvas class (that is TCanvcas::Divide()) which divides the canvas into 4 zones and sets up a Pad in each of them. Now, if we do
vega[] can.cd(1)
vega[] f1.Draw()
the function f1 will be drawn in the first Pad. All subsequent actions, draw an arrow for example, will be done on that Pad. To change the working Pad, there are three ways:
vega[] can.cd(3)
Pads are numbered from left to right and from top to bottom.
vega[] can_3.cd()
The third pad will set itself as the selected pad since you call the TPad::cd() method for the object can_3. This remark just to show the state of mind people have when they "think" in C++

II.2.7 Inheritance and data encapsulation

II.2.7.1 Inheritance

There is an obvious question that could be asked : what is the relation between a canvas and a pad ? Isn’t it almost the same thing? Yes it is. In fact, a canvas is a pad that spans through an entire window. This is nothing else than the notion of inheritance. The TPad class is the parent of the TCanvas class.
So what? The most interesting thing is that you can reuse the code written in the parent class. For example, cd() is a method that TCanvas inherits from it’s parent, TPad.

II.2.7.2 Method overriding

The method overriding is explained in chapter IV. Basically, when a class Child derives from another class Parent, it can reuse the methods defined in Parent, but if one method of Parent is not well adapted to Child, one can redefine (override) it. For example Draw() in some Child class may be different from Draw() in the Parent class. There is no ambiguity since you always specify the object : childobject.Draw() or parentobject.Draw().

II.2.8 ROOT related specifics

For what concerns inheritance, most objects in ROOT derive from a base class called TObject. This class contains everything that is shared by all the classes in ROOT. Especially, it handles
to name the most important ones.

II.3 An example of a macro

Let's try now to see how we can write a simple macro. As we've said, this is just C/C++ code. Open the editor of your choice and look at the macro named vfill_histo.C. As a matter of convention, all macros are suffixed by .C. The source code has a .cxx or .cc suffix. vfill_histo.C is the following code :

{
// Create and fill a histogram with random #'s from a Gaussian distribution.
// See http://root.cern.ch/root/HowtoHistogram.html for a brief description
// of how to use histograms in ROOT.
gROOT->Reset();
// TH1F is the equivalent of HBOOK1
// The fill data are 32 bit float points and weights are 64 bit fp.
printf("Creating Histogram...\n");
TH1F *h1 = new TH1F("h1","1-D Gaussians",100,-8,8);
printf("done.\n");
//The ROOT/CINT extensions to C++. The declaration of h1 may be
//omitted when "new" is used. So h1 = new TH1F(...) will correctly
//create an object of class "TH1F".
gRandom->SetSeed();
// Raw C types are typedefed.
Float_t xgauss;
printf("Filling Histogram...\n");
for (Int_t i=0; i < 10000; i++) {
xgauss = gRandom->Gaus(3,0.5);
h1->Fill(xgauss,0.2);
h1->Fill(xgauss-6);
}
printf(" done.\n");
}

We can try to give detailed explanations of some of the lines above.

gROOT->Reset();

This statement resets the interpreter environment, it is almost always used at the beginning of a macro but not if you want to preserve some variables that a precedent macro defined. gROOT is a global variable. We will see some more details about globals in ROOT in a few moments. gROOT is an object of the class TROOT, which represents your session. It contains, among other things, lists of named objects created during the session, such as histograms. This enables access to those objects by their name.

TH1F *h1 = new TH1F("h1","1-D Gaussians",100,-8,8);

Here, we create a histogram by invoking one of its constructors. Walking through this statement, we have :

gRandom->SetSeed();

Another global. gRandom is the current object of the class TRandom of standard random generators. You probably already noticed that all globals begin with a "g" followed by a capital letter. This is general and belongs to the coding conventions used in ROOT, which are followed by VEGA . The SetSeed() method of TRandom chooses a random seed, here the default one.
The class TRandom doesn't try to be overly ambitious. The important methods are :

Float_t xgauss;

To avoid machine dependence of raw C types (double, float, and especially int, etc...), the basic types have been typedefed. So, instead of float, we use Float_t = 4 byte float. You can equally well use standard types (float, double) for your everyday work. In VEGA, we integrated the Framelib, which has its own machine-independent data types. To avoid problems, we decided to keep both. So you can use Float_t (ROOT type) or REAL_4 (Framelib type) indifferently. We know this can be misleading but one cannot avoid some historical background...

for (Int_t i=0; i < 10000; i++) {
xgauss = gRandom->Gaus(3,0.5);
h1->Fill(xgauss,0.2);
h1->Fill(xgauss-6);
}

This seems to be a standard for loop in C in which you generate a random variable (gaussian) and you fill a histogram with this value.
For somebody not used to C++ something is strange : the Fill() method used to fill the histogram is used twice but not with the same number of arguments. This is perfectly common in C++, and it is called method overloading. We will see more about this in the next paragraph.

Now, to execute your macro type :
vega[] .x vfill_histo.C
Creating Histogram...
done
Filling Histogram...
done

Now you have in your memory (the computer one, not yours...) a histogram with which you can play. For example type
vega[] h1->Draw()
vega[] h1->Dump()

As will be seen in the chapter "Writing macros", one can write a named macro and give arguments to a macro. You also probably noticed that there is no includes in the macro. In fact, all the standard C includes are already done in the environment, as well as ROOT and VEGA specific ones.

II.3.1 C++ notions used: method overloading

We've just seen, in the example above, that a method can have different forms, with different arguments. If we look at an excerpt of the header file defining the class TH1F :

public:
virtual void Fill(Axis_t x);
virtual void Fill(Axis_t x, Stat_t w);
virtual void Fill(Axis_t x, Axis_t y, Stat_t w);
virtual void Fill(Axis_t x, Axis_t y, Axis_t z, Stat_t w);

You see that the Fill method is defined four times with different arguments. How does the compiler know what method to call ?
For the compiler to be able to make the difference, the arguments must be different enough. There is no ambiguity in the Fill methods above since the number of parameters is different for each method. If someone had made the following statement :

public:
virtual void Fill(Axis_t x);
virtual void Fill(Axis_t x, Stat_t w=1);

where in the second declaration, one of the arguments has a default value (this is permitted in C++), then the compiler doesn't know which method to call if someone uses

h1->Fill(23)

Should the compiler use the form Fill(Axis_t x); where x=23 or the form Fill(Axis_t x, Stat_t w=1); where x=23 and one uses the default value w=1 ?
In that case, the compiler sends an error message. So one must be careful, when writing his methods not to come in such situations. Easier said than done.

II.4 How to compile a macro ?

Sometimes (in fact quite often) a script may become so big or be so processing-hungry that one would like to have it compiled and not interpreted. There is included into ROOT what is called a script compiler that allows compiling very easily the scripts you are going to produce.
It starts by calling the C++ compiler that was used to build ROOT and builds a shared library. This shared library is then loaded and the function defined in the script is executed.

II.4.1 Preparation of the script

So that seems nice, what is the deal ? It’s only that you have to prepare a little bit your script. But it is quite simple. You have to
  1. NOT use extensions to C/C++ provided by the CINT interpreter. That means for example that while in the interpreter you do not need to declare variables whose type is known from the context, this is mandatory if you want to be able to compile. Since the compiler is not supposed to know the context of the interpreter. An example. In the interpreter, you can use statements like :

    c1 = new TCanvas("c1", "Test",1);

    where you do not declare the variable c1, you should do instead :

    TCanvas* c1 = new TCanvas("c1", "Test",1);

    More generally, use very standard C/C++ and declare all your variables
  2. You should add includes you use at the beginning of the file. Once again, this is for the real compiler that will do the work. Usually, the headers to be added are composed of the name of the classes used followed by the .h suffix. In case of included C code, the most commonly used are "FrameL.h" for all the Framelib calls, and the standard headers of the Virgo standard signal library.
  3. In case you want to execute immediately (i.e. use the command “.x”) the first function of the script you compile, you have to name the function in your script with the same name as the file it is contained in. For example the file my_test.C should begin with
    my_test()
    {
    your code....
    }

The tutorial script called scrollspectrum.C has been prepared this way, check it.

II.4.2 Compiling the script

What remains to be done is to compile the script. If we want to execute the script called scrollspectrum.C, we just have to do (once in the vegatutorial directory) :
vega[] .x scrollspectrum.C++
notice the ++ at the end of the command. This tells the interpreter to compile scrollspectrum.C, build a shared library called scrollspectrum.so, load this shared lib and execute scrollspectrum().
The resulting library scrollspectrum.so stays here and you can reuse it, that is reload it at a later time, with
vega[] .L scrollspectrum.so
furthermore, the scrollspectrum() function is available in the interpreter and may be used in some other script !
All this also works with loading the script after compiling :
vega[] .L scrollspectrum.C++
is a valid statement. This will build the library and load it as before. It will just not execute any function.

II.4.3 Compiling a more complex code

You will probably at one point or another try to compile a more complex code, consisting of a few files, or you will want to use the VEGA capabilities in your own code, for example use the display of vectors in a standalone executable. This is described in the chapter “How to compile your own code for VEGA or use the VEGA libraries in your code” at the end of the manual.


JavaScript must be enabled to display this email address.


Last update :27/06/2003;
Previous Next Title Page Contents