RooFit by changing one parameter

Hello all,

In roofit, I need to change one parameter in a certain interval (from 20 to 40) in the step of 1, and repeat the fit (by fixing it). It takes a lot of time do manually this fit 20 times. I am wondering is there is any function or way to perform this automatically in roofit? Thanks for the help in advance.

Cheers,
S

Hi @Shanker!

What do you mean by “manually” here, can you share your code? You mean a loop over the fixed parameter values and then do fitTo 20 times? That should take about 20 times longer than a single fit and you can’t really do better than that.

Of course you can try some of the optimizations that you can enable in RooAbsPdf::fitTo() to make the individual fits faster. Try out the NumCPU and the BatchMode option, for example!

Cheers,
Jonas

Hi Jonas,

Manually means performing the fit one be one by increasing the parameter value by the step of 1. Yeah, I want to loop over the fixed parameter values and fit it 20 times.

I am already using NumCPU to use maximum available (parallelly) core from computer, it definitely speeds up but I am looking for automated program if available in root. In other case, I’ll have to work in linux to loop the parameter values.

Thanks for the reply and please let me know if you have any suggestions.

Regards,
Shanker

Hi @Shanker,

Manually means performing the fit one be one by increasing the parameter value by the step of 1.

Yeah, I want to loop over the fixed parameter values and fit it 20 times.

To me this is the same, so I don’t understand the difference between what you are currently doing and what you want to do :smile:

Anyway, I’ll show you how I would do it and maybe this helps you. In this example, I fit a Gaussian to some toy data I generated from it. But instead of leaving all parameters floating, I fix the mean to a value that I increase in steps of one. Then I do a likelihood scan as an example, but of course you can extract any information from a RooFitResult.

void parameterScanExample1() {

   using namespace RooFit;

   RooRealVar x("x","x", 0.0, 10.0);

   RooRealVar mean("mean", "mean", 5.0, 0.0, 10.0);
   RooRealVar width("width", "width", 3.0, 0.1, 10.);

   RooGaussian model("model","model", x, mean, width);

   RooDataSet *data = model.generate(x, 2000);

   // fill the vector with scan values
   std::size_t nScanPoints = 11;
   std::vector<double> scanValuesMean(nScanPoints);
   for(int i = 0; i < nScanPoints; ++i) {
      scanValuesMean[i] = i;
   }

   // declare the parameter we want to scan over
   // as constant for the fit
   mean.setConstant(true);

   // containers to store what we care about in the fit result
   // (let's say the nll value in this example)
   std::vector<double> nllValues(nScanPoints);

   // loop over scan values and do fit
   for(int i = 0; i < nScanPoints; ++i) {
       mean.setVal(scanValuesMean[i]);
       // with the Save() option, you can get your fit result
       // as a RooFitResult and extract the information
       // you want from it
       auto fitResult = model.fitTo(*data, Verbose(false),
                                    PrintLevel(-1), Save());
       nllValues[i] = fitResult->minNll();
   }

   // print our nll results
   for(int i = 0; i < nScanPoints; ++i) {
       std::cout << "nll for mean " << scanValuesMean[i] << ": "
                 << nllValues[i] << std::endl;
   }


   // reset the state of the parameter,
   // just in case this is important for what
   // you want to do later
   mean.setConstant(false);
   mean.setVal(5.0);
}

Actually, these kind of log-likelihood scans are very common (called log-likelihood profiles), and it is supported with the RooAbsReal::createProfile function in RooFit. It also subtracts the minimum likelihood for you, so the minimum is at zero.

Here is how my example looks like when using ceateProfile:

void parameterScanExample2() {

   using namespace RooFit;

   RooRealVar x("x","x", 0.0, 10.0);

   RooRealVar mean("mean", "mean", 5.0, 0.0, 10.0);
   RooRealVar width("width", "width", 3.0, 0.1, 10.);

   RooGaussian model("model","model", x, mean, width);

   RooDataSet *data = model.generate(x, 2000);

   // fill the vector with scan values
   std::size_t nScanPoints = 11;
   std::vector<double> scanValuesMean(nScanPoints);
   for(int i = 0; i < nScanPoints; ++i) {
      scanValuesMean[i] = i;
   }

   // containers to store what we care about in the fit result
   // (let's say the nll value in this example)
   std::vector<double> nllValues(nScanPoints);

   auto* nll = model.createNLL(*data, Verbose(false),
                               PrintLevel(-1), Save());
   auto* nllProfile = nll->createProfile(mean);

   // loop over scan values and do fit
   for(int i = 0; i < nScanPoints; ++i) {
       mean.setVal(scanValuesMean[i]);
       nllValues[i] = nllProfile->getVal();
   }

   // print our nll results
   for(int i = 0; i < nScanPoints; ++i) {
       std::cout << "nll for mean " << scanValuesMean[i] << ": "
                 << nllValues[i] << std::endl;
   }
}

You can find another example of such a likelihood scan in the rf605__profilell_8C tutorial.

Of course if you are not interested in the likelihood values but in other information from the fit result, you have to follow the first example.

A third option that might be interesting if you want to avoid the overhead in fitTo() is to create the likelihood function and then instantiate a RooMinuit yourself to minimize it. This is done for example in this forum post.

I hope this helps you with your work!
Jonas

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.