Define FCN for Minuit that require parameters from main

Hello everyone,

My question is maybe more C++/code structure oriented but I wonder if some of you encountered the same difficulty and might be able to help me here !

I would like to define a fcn for Minuit to minimize, I understood this has to be a void.
However, to compute the quantity I want to minimize, I need data that I read from ROOT files within my main function. How could I define my fcn then ?

That must be an easy one but if you have any advice that would be highly appreciated :blush:

Cheers !

@moneta can you help here please?

Hi
the simplest way is to make the params global.
For example look at:
$ROOTSYS/ tutorials/fit/fit2dHist.C

Otto

Hi,

You can use the Minimizer interface of Minuit , ROOT::Math::Minimizer class. In that case you need to pass to Minuit a functor (a C++ class implementing the operator() ) and you can then use all the parameters you want as data member of the class.

See the tutorial fit/NumericalMinimization.C
https://root.cern.ch/doc/master/NumericalMinimization_8C.html

Lorenzo

Great, thanks a lot for your help @moneta I’ll try that !

Hi @moneta,

I’ve tried to implement things following your example. However I’m still getting an error :grimacing:

 error: cannot convert ‘Double_t {aka double}’ to ‘Double_t* {aka double*}’ for argument ‘1’ to ‘Double_t chi2_1D(Double_t*, Double_t, TH1D*, TF1*)’
                     ROOT::Math::Functor f(&chi2_1D(Apeak[i], slice[i], PadResponseFunction), 1);
                                                                                           ^

Compared to your example, my functor is also f and your RosenBrock is my chi2_1D.
The only difference I can see is that, to compute my chi2_1D, I need values from my ROOT file so when I compute it I passed TH1* and TF1* etc as arguments (see below).

Double_t chi2_1D(Double_t *ytrack, Double_t A_peak, TH1D* slice, TF1* PadResponseFunction)
{
    Double_t chi2 = 0;
    for (int j = 0; j < geom::nPady; j++){
        chi2 += pow(1/slice->GetBinContent(j) - (A_peak*PadResponseFunction->Eval(j+0.5 - ytrack[0]))/pow(slice->GetBinContent(j), 2), 2);
    }
    return(chi2);
}

Here is the part of my code in the main where I define and use the Minimizer.


                    // Minimize chi2 of each line to extract ytrack (https://root.cern.ch/doc/master/NumericalMinimization_8C.html)
                    ROOT::Math::Minimizer* minimum = ROOT::Math::Factory::CreateMinimizer("Minuit2", "Migrad");
                    minimum->SetMaxFunctionCalls(1000000); // for Minuit/Minuit2
                    minimum->SetMaxIterations(10000);  // for GSL
                    minimum->SetTolerance(0.001);
                    minimum->SetPrintLevel(1);

                    // create function wrapper for minimizer
                    // a IMultiGenFunction type
                    ROOT::Math::Functor f(&chi2_1D(Apeak[i], slice[i], PadResponseFunction), 1);
                    Double_t step = 0.01;
                    // starting point
                    Double_t variable = slice[i]->GetMean();
                    minimum->SetFunction(f);
                    // Set the free variables to be minimized !
                    minimum->SetVariable(0,"ytrack",variable, step);
                    // do the minimization
                    minimum->Minimize();
                    ytrack[i] = minimum->X()[0];
                    myChi2->AddBinContent(it, minimum->MinValue());

Do you have any indication on how to fix the error ? Or a workaround ?
Thanks a lot for your help,

Cheers

Marion

Hi Marion,
the 1. arg of your function is a pointer to double:

Double_t chi2_1D(Double_t *ytrack

you pass a double: (I guess APeak[i] is a double?)

ROOT::Math::Functor f(&chi2_1D(Apeak[i],

Otto

Hi Otto,

Thanks for the quick answer.
This raises for me another question then !

In the example I followed, the first argument is a pointer to a const double :

double RosenBrock(const double *xx )
{
  const Double_t x = xx[0];
  const Double_t y = xx[1];
  const Double_t tmp1 = y-x*x;
  const Double_t tmp2 = 1-x;
  return 100*tmp1*tmp1+tmp2*tmp2;
}

But when calling the function, no argument is specified

ROOT::Math::Functor f(&RosenBrock,2);

which I thought is because it’s the variable. That’s why I didn’t put the ytrack argument, because in my case it’s the variable.

So, can you clarify in which case the argument shouldn’t be specified ann in which case it’s required ?

Sorry if that’s a stupid question…

Best wishes,

Marion

Hi Marion,
sorry I didnt look carefully at your code snippet only at the
compiler error.
Your use of

ROOT::Math::Functor f(&chi2_1D(Apeak[i], slice[i], PadResponseFunction), 1);

is not correct.
The ctor of Functor takes only 2 args:
The address of the function and the dimension of the parameter array xx

double RosenBrock(const double *xx )

If you need extra data you should look at:
$ROOTSYS/tutorials/fit/line3Dfit.C
which use a function object, that is a class overwriting the () operator
or
$ROOTSYS/tutorials/fit/fitCircle.C
which uses a Lambda function.

Lorenzo @moneta please correct me if I am wrong

Otto

Hi Otto,

No problem, OK thanks a lot for the explanation I will have a look at those tutorials/examples and try again !

Thanks for the help :grin: