# Overview

Creating and using TFormula objects. Creating and drawing TF1 function objects. Fitting histograms.

# The Lesson

The material in this lesson is based on the ROOT tutorial Simple Formula and Functions

## Formulae: TFormula

TFormula encapsulates the concept of a 3 dimensional formula. A formula is specified as character string containing an expression involving:-
• The names x, y, and z: These denote the 3 dimensions.
• The terms , , ... These are elements of a parameter array. Initially, when a TFormula object is instantiated they are all set to zero but can subsequently be set, individually or collectively.
• Standard operators such as + - * / && || == != < <= > >= ...
• Standard functions such as sin, asin, sinh, exp, log ...
• Gausians, exponentials and power series that use both the dimensions and the parameter array.
• Previously defined TFormula objects.
Suppose we wish to create the formula:- 2 + 3*sin(x) This can be constructed as follows:- TFormula *my_formula = new TFormula("my_formula","2 + 3*sin(x)"); It can be evaluated at say, x = 20, with:- my_formula->Eval(20.); If we want the terms to be variable, this could be done like this:- TFormula *my_formula = new TFormula("my_formula"," + *sin(x)"); my_formula->SetParameter(0, 2.); my_formula->SetParameter(1, 3.); which results in the same formula only now the parameters can be changed during the object's lifetime. Parameters can be named using the SetParName() and SetParNames() messages. The complete parameter array can be set with the single message SetParameters().

Polynomials are denoted by:-

```  dpoln(i)

where:-
d = dimension = x(default if omitted), y or z
n = dimension of the power series
i = index of first parameter element

so:-
pol3(5) or xpol3(5) is equivalent to +*x+*x**2+*x**3
```
In a similar way:-
```  xgaus(i) is equivalent to [i]*exp(-0.5*((x-[i+1])/[i+2])**2)
xexpo(i) is equivalent to exp([i]+[i+1]*x)
```
Try this in ROOT as a simple example:- TFormula *form1 = new TFormula("form1","sqrt(abs(x))"); cout << "Value of func at 2 is: " << form1->Eval(2) << endl; cout << "Value of func at -45 is: " << form1->Eval(-45) << endl; and then ask the object about itself:- form1->Print(); Here is a trivial example of a 3 dimensional function:- TFormula *my_formula3 = new TFormula("my_formula","x + 2*y + 3*z"); my_formula3->Eval(4.,5.,6); which should yield the value 32. For more details see TFormula

## Functions: TF1, TF2, TF3

Functions build on the concept of formulae:-
• They can be 1, 2 or 3 dimensional: TF1, TF2 and TF3 respectively.
• They are bounded in all dimensions.
• The underlying formula can either be a TFormula object or a user written C function.
• They can draw, integrate and differentiate themselves.
• They can be passed to histogram objects for fitting.
As a demonstration of a TF1 object, create the file:- function.cxx containing:- { gROOT->Reset(); TCanvas *c1 = new TCanvas("c1","Example with Formula",200,10,700,500); c1->SetGridx(); c1->SetGridy(); TF1 *fun1 = new TF1("fun1","abs(sin(x)/x)",0,10); fun1->Draw(); c1->Update(); } The TF1 object is is bounded between 0 and 10. Run ROOT and execute this macro.

As we shall see shortly the TF1, TF2, TF3 classes are used in histogram fitting. They inherit from TFormula and the parameters of the TFormula object are used as the fit parameters. Flexible though TFormula is, it can only describe a simple analytic form and there are times when the form of a fitted function needs to be more complex. To allow for this, TF1, TF2 and TF3 can take a user C defined function. The function definition is of the form:-

Double_t func( Double_t *x, Double_t *parm ); This appears to be a function that takes two pointers to Double_t (double precision) and returns a Double_t. In fact the 2 arguments are arrays. In C++, a single dimensional array is essentially a pointer to the first array element. The two arguments are:-
• Array x - array containing x, (and possibly y and z - for 2D and 3D functions).
• Array parm - array of fit parameters.
As a simple example, consider the following:- Double_t my_c_func ( Double_t *x, Double_t *parm) { return parm + parm*x; } void test_c_func() { TF1 *my_f1 = new TF1("my_f1", my_c_func, 0., 10., 2); my_f1->SetParameters(2.,3.); my_f1->Draw(); } This first defines a function called my_c_func that describes a straight line with parm as the constant term and parm as the slope:- Double_t my_c_func ( Double_t *x, Double_t *parm) { return parm + parm*x; } Next comes a function to test this. It creates a TF1 object:- void test_c_func() { TF1 *my_f1 = new TF1("my_f1", my_c_func, 0., 10., 2); Note how the TF1 constructor is passed my_c_func as argument. C++ doesn't pass the functions as arguments, but whenever a function identifier appears without the trailing (), then the compiler knows that this is not a function call, and takes the reference to mean a pointer to function. Pointers to functions can get rather complicated, but all we need to know is that the TF1 object now has a pointer to my_c_func, and can call it when it needs to. The TF1 constructor is also passed the function limits 0., 10. and the number of parameters 2. It did not need the number of parameters when using a TFormula, it could determined it from the expression, but with a C function it has no way of knowing.

Now the parameters are loaded and finally the TF1 draws itself for the line 2 + 3x:-

my_f1->SetParameters(2.,3.); my_f1->Draw(); } To run the above:-
1. Create a file called tf1.cxx containing the above.
2. Run ROOT.
3. Load the code: .L tf1.cxx
4. Call the test function: test_c_func();

## Fitting

One of the main uses for TF1, TF2 and TF3 are as fitting objects for histograms. To demonstrate this we will generate a histogram of the form:- exp(-0.5*x) and then fit it. This is how it is done:- { #include <math.h> gROOT->Reset(); my_canvas = new TCanvas("my_canvas","Histogram Example",200,10,600,400); // Generate the histogram TH1F *hist = new TH1F("hist","Exponential distribution",100,0.,5.); hist->SetFillColor(3); hist->Draw(); gRandom->SetSeed(); Float_t data; Int_t dummy; for ( Int_t i=0; i<10000; i++) { data = - log( gRandom->Rndm(dummy) ) / 0.5; hist->Fill(data); if ( i%500 == 0 ) { my_canvas->Modified(); my_canvas->Update(); } } // Fit the histogram. TF1 *my_func = new TF1("my_func","xexpo(0)",0.,5.); my_func->SetParameters(1.,-1.); my_func->Print(); hist->Fit( "my_func" ); my_func->Draw("same"); } The first part of the macro creates a TCanvas and a TH1F which it draws and fills with the required exponential. This is taken almost straight from the Histograms lesson. Next a TF1 object is created using a TFormula expression for an exponential in x:- TF1 *my_func = new TF1("my_func","xexpo(0)",0.,5.); The two parameters are set to some nominal initial value, and the Tf1 prints itself:- my_func->SetParameters(1.,-1.); my_func->Print(); Although the initial values are nominal, it does appear that they cannot be totally arbitrary, some values can cause fitter problems.

The next line is were all the action takes place:-

hist->Fit( "my_func" ); The histogram is asked to fit itself and is passed the TF1 object. Two points are worthy of note:-
• Its not a pointer to TF1 object that is passed, but its name. ROOT's ability to access objects by name was a subject dealt with in the Inheritance lesson. It so happens that in this case the name of the TF1 object (the first arg in its constructor) is the same as the name of its pointer. That's a common convention, but nothing more, its the object name that the Fit() message requires.
• This is a miniature example of a typical OO program, passing one object to another and then letting them interact to achieve a task. The TF1 object "knows all about" functions, including how to draw them. The TH1F object "knows all about histograms" including how to fit them using the abstraction of a function which TF1 implements.
Finally, having had its parameters fitted, the TF1 object is asked to draw itself:- my_func->Draw("same"); The "same" argument, ensures that the canvas is not cleared so that the fit can be superimposed on the histogram. This is the final result:- # Summary

• TFormula are objects that encapsulate the concept of an expression in x, y and z. The expression can involve user assignable parameters, standard maths functions and operators. For example:- TFormula *my_formula = new TFormula("my_formula"," + *sin(x)"); my_formula->SetParameter(0, 2.); my_formula->SetParameter(1, 3.); my_formula->Eval(20.); evaluates 2 + 3*sin(20.) The full list of supported expressions can be found in TFormula

• TF1, TF2 and TF3 represent 1, 2 and 3 dimensional functions that can be based on TFormula objects or user written C functions. Functions can draw, differentiate and integrate themselves and are used as the basis for histogram fitting. For example:- TF1 *fun1 = new TF1("fun1","abs(sin(x)/x)",0,10); fun1->Draw()
• TF1, TF2 and TF3 objects whose Tformula, or user C function, involves parameters can be passed to histogram's Fit() message:- my_hist->Fit(my_tf1) After fitting the TF1, TF2 and TF3 object's parameters hold the fit result.

Go Back to the The First Steps Top Page

If you have any comments about this page please send them to Nick West