RooFit by changing one parameter

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