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.
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âŚ
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?
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 âŚ
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?
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
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.
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)
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.