2D Maximum Likelihood Unbinned Fit

Hello ROOTers,

I’ve been trying to make a 2 dimensional unbinned likelihood fit using a ROOT::Math::bigaussian_pdf. The code seems to work but the minimization does not converge. I always get “Invalid FitResult (status = 4)” even when I set the initial values of the parameters really close to the expected result. Here is the main part of the code that I wrote following the guide.

TFile *inFile = TFile::Open((fileName).c_str(),"UPDATE");
TTree *tree = (TTree*)inFile->Get("treeNAME");
// Extract data from tree
int nevt = tree->Draw("Xt:Yt","","goff");
double *Xt = tree->GetV1();
double *Yt = tree->GetV2();
ROOT::Fit::UnBinData data(nevt, Xt, Yt);
TF2 *f1 = new TF2("f1", "ROOT::Math::bigaussian_pdf(x, y, [1], [3], [4], [0], [2])", -10., 11., -10., 11.);
f1->SetParNames("x0", "sigmax", "y0", "sigmay", "rho"); // note: -1 < rho < 1
f1->SetParameter(0, x0);
f1->SetParameter(1, sx);
f1->SetParameter(2, y0);
f1->SetParameter(3, sy);
f1->SetParameter(4, 0.01);
f1->SetParLimits(4,-1,1);
// Fit
ROOT::Math::WrappedMultiTF1 fitFunction(*f1, f1->GetNdim());
ROOT::Fit::Fitter fitter;
fitter.SetFunction(fitFunction, false);
fitter.LikelihoodFit(data);
ROOT::Fit::FitResult r=fitter.Result();
r.Print(std::cout);

You can also find a working example here
ROOTunbinFit2D.C (4.7 KB)
Does anybody have an idea of what I’m missing?

Cheers,
Francesco


ROOT Version: 6.24/06
Platform: Ubuntu 20.04.4 LTS


Hello,

@moneta can perhaps give a hand, thanks!

Hi,
It was not easy, but I found at the end the problem of your code.

You are using this to create a data set for fitting from the TTree:

// Extract data from tree
int nevt = tree->Draw("Xt:Yt","","goff");
double *Xt = tree->GetV1();
double *Yt = tree->GetV2();
ROOT::Fit::UnBinData data(nevt, Xt, Yt);

This is fine, but one should note that in this case the data values are not copied but just used externally and only the pointers are copied in the UnBinData class. The problem is that later you call again TTree::Draw to get the histograms for X and Y and this make the UnBinData class having pointers to wrong values. You can do many things, for example:

  • don’t make histogram for just the mean and stddev of the data. You can just use TMath::Mean and TMath::StdDev` using the Xt and Yt arrays
  • copy the data in some local arrays, and use those to pass to UnBinData, like:
std::vector<double> Xt(  tree->GetV1(),  tree->GetV1() + next); 
std::vector<double> Yt(  tree->GetV2(),  tree->GetV2() + next); 
ROOT::Fit::UnBinData data(nevt, Xt.data(), Yt.data());
  • use UnBinData::Add(x,y) that is copying the data
int nevt = tree->Draw("Xt:Yt","","goff");
double *Xt = tree->GetV1();
double *Yt = tree->GetV2();
ROOT::Fit::UnBinData data(nevt,2); // 2 is the data dimension
for (int i = 0; i < next; i++)
   data.Add(Xt[i], Yt[i]);

See ROOT: ROOT::Fit::UnBinData Class Reference

Best regards

Lorenzo

Many thanks @moneta !
Your explanation was extremely helpful. I had not fully understood what tree->Draw() was doing.
I followed your first suggestion and everything worked out great

double_t x0 = TMath::Mean(nevt, Xt);
double_t sx = TMath::StdDev(nevt, Xt);
... (same for Y)

Best regards,
Francesco

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