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
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