SetFcn

Is it possible to call SetFCN in PyROOT with python function as a parameter? In my code I have

TVirtualFitter.Fitter(g).SetFCN(twoPartParabFCN)

where g is a TGraph and twoPartParabFCN starts as:

def twoPartParabFCN(nPar, grad, fval, par, iflag):

but I receive the following error:

Any help appreciated :slight_smile:

Hi,

in order to pass python functions, a C++ callback needs to exist. Since C++ functions can not be created on the fly, these xyzFCN() functions that take them need to be individually “pythonized.” This is done for TMinuit and Fit::TFitter, but not for ::TFitter (::TVirtualFitter). So unless the underlying fitter is actually TMinuit (and available through gMinuit), this call won’t work at the moment.

Cheers,
Wim

The underlying fitter is in this case TMinuit. However, gMinuit.SetFCN does not seem to take any effect - the FCN function is not called (does not print). Tomorrow I’ll send the code to which I do not have access at the moment of writing this…

OK, I am not sure, how to gMinuit.SetFCN() for use with TGraph::Fit.

When I call

TVirtualFitter.SetDefaultFitter("Minuit")
print gMinuit

No proper object is in gMinuit in this case and gMinuit.SetFCN() cannot be called.

In case of:

TVirtualFitter.SetDefaultFitter("Minuit")
TVirtualFitter.Fitter(g)

There is an initialized object in gMinuit and gMinuit.SetFCN() can be called, but it does not affect g.Fit(“U”) (where g is a TGraph). So how to do this properly?

Hi,

can you send a runnable script? Thanks!

Cheers,
Wim

Here it goes. If you uncomment line with

#f = TVirtualFitter.Fitter(g, 5)

it does not display error, but does not use FCN. If the line is commented, SetFCN on gMinuit does not work.
test_gminuit.py (800 Bytes)

Hi,

AFAICS the “g.Fit(a, “U”)” method at least works in that it calls twoPartParab.

For the method through gMinuit, the code underneath is actually using TMinuitFitter and not TMinuit. This uses gMinuit2, not gMinuit. Since the pythonized method is associated with the class, gMinuit2 won’t have it.

So, I’m out of options as to how to fix this. Another complication is that the TMinuitFitter is not made available in a dictionary, it’s base class TFitter is. Thus, I can not distinguish between a TFitter and a TMinuitFitter when pythonizing the class. I do not have enough knowledge of the TFumiliFitter to know whether it and the TMinuitFitter are interchangeable.

Anyway, I added a SetFCN to TFitter, which then works for TMinuitFitter, but you’ll need trunk for that. Best I can think of if g.Fit() does not suffice …

Cheers,
Wim

I’ve a question about SetFCN and passing pointers (a.k.a.: difference between C++ and python).

If I want set a function for minimizing, I use

TheMinuit = TMinuit(2)
TheMinuit.SetFCN(myClass::myFunc)

In C++ the myFunc should be done in such way:

void myClass::myFunc(double& value, double* par) {
   double chi2 = 0.
   for (int i = 0; i < myClass::Xvalue.size(); i++) {
      fx = myClass::Xvalue[i]*par[1] + par[0]
      y =  myClass::Yvalue[i]
      ey = myClass::YvalueError[i]
      chi2 += pow((y-fx)/ey, 2)
   }
   if (chi2 <1e30) value = chi2
   else                 value = 1e30
}

In python how work the passaging of the ‘value’ variable? I mean, ‘SetFCN’ WANT a void function, so I cannot write in python ‘return value’, is it? And ‘par’ should be a numpy.array(par), is it not?

Thanks for the help and clarifications…

Hi,

the signature you have in that C++ function does not appear to be correct? It should conform to this:

virtual void SetFCN(void (*fcn)(Int_t &, Double_t *, Double_t &f, Double_t *, Int_t));

Anyway, the python function equivalent takes buffers, so index it with 0 and assign to it. For example (from roottest):[code]def fcn( npar, gin, f, par, iflag ):
global ncount
nbins = 5

calculate chisquare

chisq, delta = 0., 0.
for i in range(nbins):
delta = (z[i]-func(x[i],y[i],par))/errorz[i]
chisq += delta*delta

f[0] = chisq
ncount += 1[/code]
Cheers,
Wim

Ok, Thank you!!!

P.S.: not necessary… there are 2 possible prototype:

virtual void SetFCN(void* fcn);
virtual void SetFCN(void (*fcn)(Int_t &, Double_t *, Double_t &f, Double_t *, Int_t));

Hi,

the first prototype is for CINT and the functions passed through should still conform to the same interface. This is the body of that SetFCN(void*) function: const char *funcname = gCint->Getp2f2funcname(fcn); if (funcname) { fMethodCall = new TMethodCall(); fMethodCall->InitWithPrototype(funcname,"Int_t&,Double_t*,Double_t&,Double_t*,Int_t"); }
and as you can see, it sets up the same parameters for the call, so yes, it too needs to conform.

Cheers,
Wim

Well, SetFCN works, but… I cannot get any proper results. It seems like fval from the FCN is not properly passed to the fitter and is always 0 (according to the verbose output). I attach the script…
test_gminuit.py (956 Bytes)

Hi,

yes, of course if you code it like that: standard python “problem” that assignment to a variable merely moves the reference; it does not overwrite the value of the original object pointed to by the variable. Therefore, fval is actually made to be a buffer, so do:fval[0] = chi2and things should work in that the C++ side will receive the value.

Cheers,
Wim

Thanks, my adventure with python begun quite a short time ago… :slight_smile: