Syntax of a free function (or C++ functor) for TGraph fitting

Hi there,

I’m currently trying to integrate the enclosed area of a TGraph and the x-axis in a certain x-range (I’ve attached a pdf showing it).
As I’ve figured out now, TGraph.Integral() is not the correct method for that.

In another thread, Lorenzo has suggested to use a free function or a C++ functor to fit the TGraph (and then just integrate the fit function). Locate like command
However, I’m clueless about how I can implement the free function, such that it works from pyroot.
The C++ syntax by Lorenzo is

struct MyFunction { MyFunction(TGraph & g) : fGraph(&g) {} double operator() (double *x, double *) { return fGraph->Eval(x[0]); } TGraph * fGraph; };
and in principal, I’d like to call it like this:

Graph = ROOT.TGraph(n, xarr, yarr)

# Declaration of MyFunction here

f1 = ROOT.TF1("f1", )
Graph.Fit("f1")
Integral = f1.Integral(xlow, xhigh)

The troubling point where I’m stuck now, is that it’s not a function but a general function object.

Does anybody have an idea? Thanks a lot!
I’m using root version 5.34/32.
TGraphAlphaToProb.pdf (16.2 KB)

Hi,

you need to provide the dictionary for MyFunction, selecting it with a linkdef file, creating a dictionary and compiling the library.
Alternatively, you can move to ROOT6 and JIT the function and access it directly from within Python, like this:

import ROOT
ROOT.gInterpreter.ProcessLine('''
struct MyFunction {
   MyFunction(TGraph & g) : fGraph(&g) {}
   double operator() (double *x, double *) { return fGraph->Eval(x[0]); }
   TGraph * fGraph;
};
''')
# suppose your graph is called "mygraph"
myf = ROOT.MyFunction(mygraph)
f1 = ROOT.TF1("f1", myf)
[...]

Cheers,
D

Thanks a lot for the fast answer!
I’ve switched to Root 6 (6.08.00), but with the following example

import ROOT
graph_1 = ROOT.TGraph(n, x_arr, y_arr) #arr created with the array module 

ROOT.gInterpreter.ProcessLine('''
struct MyFunction {
   MyFunction(TGraph & g) : fGraph(&g) {}
   double operator() (double *x, double *) { return fGraph->Eval(x[0]); }
   TGraph * fGraph;
};''')
myf = ROOT.MyFunction(graph_1)
ffree = ROOT.TF1("ffree", myf)
Integral = f1.Integral(0, 0.003)

I get a crash when calling f1.Integral (or also by saving the canvas with the drawn f1).
Because of my limited C++ knowledge, I’ve tried to replace the x (and g) in the struct with x_arr (graph_1), but it also crashed. I think that something with MyFunction is wrong (i.e. it doesn’t return Eval to the TF1), but I don’t know how to fix it.
I’ve attached the log of the crash.
LogCrash.txt (6.31 KB)

Alternatively, with Root6, one could use the lambda operator (Integral of TGraph)

TF1 f1("f",[&](double *x, double *){ return g.Eval(x[0]); },1,10,0); double integral = f1.Integral(1,10);
, but I’m also clueless about how to call like this from python (I guess giving the python lambda doesn’t work).

Hi,

thanks for moving to 6.08: this is a modern release, I am sure you’ll find the enormous set of new features very useful to boost your research.
I corrected a typo and remanipulated the script: this works.

import ROOT
graph_1 = ROOT.TGraph(2)
graph_1.SetPoint(0,0,0)
graph_1.SetPoint(0,1,1)

ROOT.gInterpreter.ProcessLine('''
struct MyFunction {
   MyFunction(TGraph & g) : fGraph(&g) {}
   double operator() (double *x, double *) { return fGraph->Eval(x[0]); }
   TGraph * fGraph;
};
''')

myf = ROOT.MyFunction(graph_1)
ffree = ROOT.TF1("ffree", myf,0,10,1) # <- note the 1
Integral = ffree.Integral(0, 1)
print Integral

Cheers,
D

Thanks a lot for developing ROOT and also for providing excellent support!

The arguments in the TF1 fixed it, now it works like a charm :smiley:

Hi,

great that you could move forward!
We’ll try to make the operation you carried out even easier from the next release.

Cheers,
Danilo