#include "TH1.h" #include "TH2.h" #include "TF1.h" #include "TF2.h" #include "TGraphErrors.h" #include "TGraphAsymmErrors.h" #include "TGraph2DErrors.h" #include "TSystem.h" #include "TRandom3.h" #include "TROOT.h" #include "TVirtualFitter.h" #include "Fit/BinData.h" #include "Fit/UnBinData.h" #include "HFitInterface.h" #include "Fit/Fitter.h" #include "Math/WrappedMultiTF1.h" #include "Math/WrappedParamFunction.h" #include "Math/WrappedTF1.h" //#include "Math/Polynomial.h" #include "RConfigure.h" #include #include #include // print the data void printData(const ROOT::Fit::BinData & data) { std::cout << "Bin data, point size is " << data.PointSize() << " data dimension is " << data.NDim() << " type is " << data.GetErrorType() << std::endl; for (unsigned int i = 0; i < data.Size(); ++i) { if (data.GetErrorType() == ROOT::Fit::BinData::kNoError) std::cout << data.Coords(i)[0] << " " << data.Value(i) << std::endl; else if (data.GetErrorType() == ROOT::Fit::BinData::kValueError) std::cout << data.Coords(i)[0] << " " << data.Value(i) << " +/- " << data.Error(i) << std::endl; else if (data.GetErrorType() == ROOT::Fit::BinData::kCoordError) { double ey = 0; const double * ex = data.GetPointError(i,ey); std::cout << data.Coords(i)[0] << " +/- " << ex[0] << " " << data.Value(i) << " +/- " << ey << std::endl; } else if (data.GetErrorType() == ROOT::Fit::BinData::kAsymError) { double eyl = 0; double eyh = 0; const double * ex = data.GetPointError(i,eyl,eyh); std::cout << data.Coords(i)[0] << " +/- " << ex[0] << " " << data.Value(i) << " - " << eyl << " + " << eyh << std::endl; } } std::cout << "\ndata size is " << data.Size() << std::endl; } void printData(const ROOT::Fit::UnBinData & data) { for (unsigned int i = 0; i < data.Size(); ++i) { std::cout << data.Coords(i)[0] << "\t"; } std::cout << "\ndata size is " << data.Size() << std::endl; } int compareResult(double v1, double v2, std::string s = "", double tol = 0.01) { // compare v1 with reference v2 // give 1% tolerance if (std::abs(v1-v2) < tol * std::abs(v2) ) return 0; std::cerr << s << " Failed comparison of fit results \t chi2 = " << v1 << " it should be = " << v2 << std::endl; return -1; } double chi2FromFit(const TF1 * func ) { // return last chi2 obtained from Fit method function assert(TVirtualFitter::GetFitter() != 0 ); return (TVirtualFitter::GetFitter()->Chisquare(func->GetNpar(), func->GetParameters() ) ); } int testHisto1DFit() { std::string fname("gaus"); TF1 * func = (TF1*)gROOT->GetFunction(fname.c_str()); func->SetParameter(0,10); func->SetParameter(1,0); func->SetParameter(2,3.0); TRandom3 rndm; int iret = 0; double chi2ref = 0; // fill an histogram TH1D * h1 = new TH1D("h1","h1",30,-5.,5.); // h1->FillRandom(fname.c_str(),100); for (int i = 0; i <1000; ++i) h1->Fill( rndm.Gaus(0,1) ); h1->Print(); //h1->Draw(); // gSystem->Load("libMinuit2"); // gSystem->Load("libFit"); // ROOT::Fit::DataVector dv; ROOT::Fit::BinData d; ROOT::Fit::FillData(d,h1,func); printData(d); // create the function ROOT::Math::WrappedMultiTF1 wf(*func); // need to do that to avoid gradient calculation ROOT::Math::IParamMultiFunction & f = wf; double p[3] = {100,0,3.}; f.SetParameters(p); // create the fitter ROOT::Fit::Fitter fitter; bool ret = fitter.Fit(d, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Fit Failed " << std::endl; return -1; } chi2ref = fitter.Result().Chi2(); // compare with TH1::Fit TVirtualFitter::SetDefaultFitter("Minuit2"); std::cout << "\n******************************\n\t TH1::Fit Result \n" << std::endl; func->SetParameters(p); h1->Fit(func); iret |= compareResult( chi2FromFit(func), chi2ref,"1D histogram chi2 fit"); // test using binned likelihood std::cout << "\n\nTest Binned Likelihood Fit" << std::endl; ROOT::Fit::DataOptions opt; opt.fUseEmpty = true; ROOT::Fit::BinData dl(opt); ROOT::Fit::FillData(dl,h1,func); ret = fitter.LikelihoodFit(dl, f); f.SetParameters(p); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Binned Likelihood Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"1D histogram likelihood fit",0.3); // compare with TH1::Fit std::cout << "\n******************************\n\t TH1::Fit Result \n" << std::endl; func->SetParameters(p); h1->Fit(func,"L"); iret |= compareResult(func->GetChisquare(),fitter.Result().Chi2(),"TH1::Fit likelihood ",0.001); //std::cout << "Equivalent Chi2 from TF1::Fit " << func->GetChisquare() << std::endl; std::cout << "\n\nTest Chi2 Fit using integral option" << std::endl; // need to re-create data opt = ROOT::Fit::DataOptions(); opt.fIntegral = true; ROOT::Fit::BinData d2(opt); ROOT::Fit::FillData(d2,h1,func); f.SetParameters(p); ret = fitter.Fit(d2, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Integral Chi2 Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"1D histogram integral chi2 fit",0.2); // compare with TH1::Fit std::cout << "\n******************************\n\t TH1::Fit Result \n" << std::endl; func->SetParameters(p); h1->Fit(func,"I"); iret |= compareResult(func->GetChisquare(),fitter.Result().Chi2(),"TH1::Fit integral ",0.001); // test integral likelihood opt = ROOT::Fit::DataOptions(); opt.fIntegral = true; opt.fUseEmpty = true; ROOT::Fit::BinData dl2(opt); ROOT::Fit::FillData(dl2,h1,func); f.SetParameters(p); ret = fitter.LikelihoodFit(dl2, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Integral Likelihood Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"1D histogram integral likelihood fit",0.3); // compare with TH1::Fit std::cout << "\n******************************\n\t TH1::Fit Result \n" << std::endl; func->SetParameters(p); h1->Fit(func,"IL"); //std::cout << "Equivalent Chi2 from TF1::Fit " << func->GetChisquare() << std::endl; iret |= compareResult(func->GetChisquare(),fitter.Result().Chi2(),"TH1::Fit likelihood integral ",0.001); // redo chi2fit std::cout << "\n\nRedo Chi2 Hist Fit" << std::endl; f.SetParameters(p); ret = fitter.Fit(d, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"1D histogram chi2 fit (2)",0.001); // test grapherrors fit std::cout << "\n\nTest Same Fit from a TGraphErrors - no coord errors" << std::endl; TGraphErrors gr(h1); ROOT::Fit::BinData dg; dg.Opt().fCoordErrors = false; // do not use coordinate errors (default is using ) ROOT::Fit::FillData(dg,&gr); f.SetParameters(p); ret = fitter.Fit(dg, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Graph Errors Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"TGraphErrors chi2 fit",0.001); // fit using error on X std::cout << "\n\nTest Same Fit from a TGraphErrors - use coord errors" << std::endl; ROOT::Fit::BinData dger; // not needed since they are used by default //dger.Opt().fCoordErrors = true; // use coordinate errors dger.Opt().fUseEmpty = true; // this will set error 1 for the empty bins ROOT::Fit::FillData(dger,&gr); f.SetParameters(p); ret = fitter.Fit(dger, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Graph Errors Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"TGraphErrors effective chi2 fit ",0.7); // compare with TGraphErrors::Fit std::cout << "\n******************************\n\t TGraphErrors::Fit Result \n" << std::endl; func->SetParameters(p); // set error = 1 for empty bins for (int ip = 0; ip < gr.GetN(); ++ip) if (gr.GetErrorY(ip) <= 0) gr.SetPointError(ip, gr.GetErrorX(ip), 1.); gr.Fit(func); std::cout << "Ndf of TGraphErrors::Fit = " << func->GetNDF() << std::endl; iret |= compareResult(func->GetChisquare(),fitter.Result().Chi2(),"TGraphErrors::Fit ",0.001); // test graph fit (errors are 1) do a re-normalization std::cout << "\n\nTest Same Fit from a TGraph" << std::endl; fitter.Config().SetNormErrors(true); TGraph gr2(h1); ROOT::Fit::BinData dg2; ROOT::Fit::FillData(dg2,&gr2); f.SetParameters(p); ret = fitter.Fit(dg2, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Graph Fit Failed " << std::endl; return -1; } //iret |= compareResult(fitter.Result().Chi2(), chi2ref,"TGraph fit (no errors) ",0.3); // compare with TGraph::Fit (no errors) std::cout << "\n******************************\n\t TGraph::Fit Result \n" << std::endl; func->SetParameters(p); gr2.Fit(func); std::cout << "Ndf of TGraph::Fit = " << func->GetNDF() << std::endl; iret |= compareResult(func->GetChisquare(),fitter.Result().Chi2(),"TGraph::Fit ",0.001); // reddo chi2fit using Fumili2 std::cout << "\n\nRedo Chi2 Hist Fit using FUMILI2" << std::endl; f.SetParameters(p); fitter.Config().SetMinimizer("Minuit2","Fumili"); ret = fitter.Fit(d, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"1D Histo Fumili2 fit "); // reddo chi2fit using old Fumili std::cout << "\n\nRedo Chi2 Hist Fit using FUMILI" << std::endl; f.SetParameters(p); fitter.Config().SetMinimizer("Fumili"); ret = fitter.Fit(d, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"1D Histo Fumili fit "); // test using GSL multi fit (L.M. method) std::cout << "\n\nRedo Chi2 Hist Fit using GSLMultiFit" << std::endl; f.SetParameters(p); fitter.Config().SetMinimizer("GSLMultiFit"); ret = fitter.Fit(d, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"1D Histo GSL NLS fit "); // test using GSL multi min method std::cout << "\n\nRedo Chi2 Hist Fit using GSLMultiMin" << std::endl; f.SetParameters(p); fitter.Config().SetMinimizer("GSLMultiMin","BFGS2"); ret = fitter.Fit(d, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"1D Histo GSL Minimizer fit "); return iret; } class Func1D : public ROOT::Math::IParamFunction { public: void SetParameters(const double *p) { std::copy(p,p+NPar(),fp);} const double * Parameters() const { return fp; } ROOT::Math::IGenFunction * Clone() const { Func1D * f = new Func1D(); f->SetParameters(fp); return f; }; unsigned int NPar() const { return 3; } private: double DoEvalPar( double x, const double *p) const { return p[0]*x*x + p[1]*x + p[2]; } double fp[3]; }; // gradient 2D function class GradFunc2D : public ROOT::Math::IParamMultiGradFunction { public: void SetParameters(const double *p) { std::copy(p,p+NPar(),fp);} const double * Parameters() const { return fp; } ROOT::Math::IMultiGenFunction * Clone() const { GradFunc2D * f = new GradFunc2D(); f->SetParameters(fp); return f; }; unsigned int NDim() const { return 2; } unsigned int NPar() const { return 5; } void ParameterGradient( const double * x, const double * , double * grad) const { grad[0] = x[0]*x[0]; grad[1] = x[0]; grad[2] = x[1]*x[1]; grad[3] = x[1]; grad[4] = 1; } private: double DoEvalPar( const double *x, const double * p) const { return p[0]*x[0]*x[0] + p[1]*x[0] + p[2]*x[1]*x[1] + p[3]*x[1] + p[4]; } // double DoDerivative(const double *x, unsigned int icoord = 0) const { // assert(icoord <= 1); // if (icoord == 0) // return 2. * fp[0] * x[0] + fp[1]; // else // return 2. * fp[2] * x[1] + fp[3]; // } double DoParameterDerivative(const double * x, const double * p, unsigned int ipar) const { std::vector grad(NPar()); ParameterGradient(x, p, &grad[0] ); return grad[ipar]; } double fp[5]; }; int testHisto1DPolFit() { std::string fname("pol2"); TF1 * func = (TF1*)gROOT->GetFunction(fname.c_str()); func->SetParameter(0,1.); func->SetParameter(1,2.); func->SetParameter(2,3.0); TRandom3 rndm; int iret = 0; double chi2ref = 0; // fill an histogram TH1D * h2 = new TH1D("h2","h2",30,-5.,5.); // h1->FillRandom(fname.c_str(),100); for (int i = 0; i <1000; ++i) h2->Fill( func->GetRandom() ); // fill fit data ROOT::Fit::BinData d; ROOT::Fit::FillData(d,h2,func); printData(d); // create the function Func1D f; double p[3] = {100,0,3.}; f.SetParameters(p); // create the fitter //std::cout << "Fit parameter 2 " << f.Parameters()[2] << std::endl; std::cout << "\n\nTest histo polynomial fit using Fitter" << std::endl; ROOT::Fit::Fitter fitter; bool ret = fitter.Fit(d, f); if (ret) fitter.Result().Print(std::cout,true); else { std::cout << " Fit Failed " << std::endl; return -1; } chi2ref = fitter.Result().Chi2(); // compare with TH1::Fit std::cout << "\n******************************\n\t TH1::Fit(pol2) Result \n" << std::endl; func->SetParameters(p); h2->Fit(func,"F"); iret |= compareResult(func->GetChisquare(),chi2ref,"TH1::Fit ",0.001); std::cout << "\n\nTest histo polynomial linear fit " << std::endl; ROOT::Math::WrappedTF1 pf(*func); //ROOT::Math::Polynomial pf(2); pf.SetParameters(p); fitter.Config().SetMinimizer("Linear"); ret = fitter.Fit(d, pf); if (ret) { fitter.Result().Print(std::cout); fitter.Result().PrintCovMatrix(std::cout); } else { std::cout << " Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(),chi2ref,"1D histo linear Fit "); // compare with TH1::Fit std::cout << "\n******************************\n\t TH1::Fit(pol2) Result with TLinearFitter \n" << std::endl; func->SetParameters(p); h2->Fit(func); iret |= compareResult(func->GetChisquare(),fitter.Result().Chi2(),"TH1::Fit linear",0.001); return iret; } int testHisto2DFit() { // fit using a 2d parabola (test also gradient) std::string fname("pol2"); TF2 * func = new TF2("f2d",ROOT::Math::ParamFunctor(GradFunc2D() ), 0.,10.,0,10,5); double p0[5] = { 1.,2.,0.5,1.,3. }; func->SetParameters(p0); assert(func->GetNpar() == 5); TRandom3 rndm; double chi2ref = 0; int iret = 0; // fill an histogram TH2D * h2 = new TH2D("h2d","h2d",30,0,10.,30,0.,10.); // h1->FillRandom(fname.c_str(),100); for (int i = 0; i <10000; ++i) { double x,y = 0; func->GetRandom2(x,y); h2->Fill(x,y); } // fill fit data ROOT::Fit::BinData d; ROOT::Fit::FillData(d,h2,func); //printData(d); // create the function GradFunc2D f; double p[5] = { 2.,1.,1,2.,100. }; f.SetParameters(p); // create the fitter ROOT::Fit::Fitter fitter; //fitter.Config().MinimizerOptions().SetPrintLevel(3); fitter.Config().SetMinimizer("Minuit2"); std::cout <<"\ntest 2D histo fit using gradient" << std::endl; bool ret = fitter.Fit(d, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Gradient Fit Failed " << std::endl; return -1; } chi2ref = fitter.Result().Chi2(); // test without gradient std::cout <<"\ntest result without using gradient" << std::endl; ROOT::Math::WrappedParamFunction f2(&f,2,5,p); ret = fitter.Fit(d, f2); if (ret) fitter.Result().Print(std::cout); else { std::cout << " Chi2 Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"2D histogram chi2 fit"); // test Poisson bin likelihood fit (no gradient) std::cout <<"\ntest result without gradient and binned likelihood" << std::endl; f.SetParameters(p); fitter.SetFunction(static_cast(f) ); fitter.Config().ParSettings(0).SetLimits(0,100); fitter.Config().ParSettings(1).SetLimits(0,100); fitter.Config().ParSettings(2).SetLimits(0,100); fitter.Config().ParSettings(3).SetLimits(0,100); fitter.Config().ParSettings(4).SetLowerLimit(0); //fitter.Config().MinimizerOptions().SetPrintLevel(3); ret = fitter.LikelihoodFit(d); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Poisson 2D Bin Likelihood Fit Failed " << std::endl; return -1; } // test binned likelihood gradient std::cout <<"\ntest result using gradient and binned likelihood" << std::endl; f.SetParameters(p); fitter.SetFunction(f); //fitter.Config().MinimizerOptions().SetPrintLevel(3); fitter.Config().ParSettings(0).SetLimits(0,100); fitter.Config().ParSettings(1).SetLimits(0,100); fitter.Config().ParSettings(2).SetLimits(0,100); fitter.Config().ParSettings(3).SetLimits(0,100); fitter.Config().ParSettings(4).SetLowerLimit(0); ret = fitter.LikelihoodFit(d); if (ret) { // redo fit releasing the parameters f.SetParameters(&(fitter.Result().Parameters().front()) ); ret = fitter.LikelihoodFit(d,f); } if (ret) fitter.Result().Print(std::cout); else { std::cout << "Gradient Bin Likelihood Fit Failed " << std::endl; return -1; } // test with linear fitter std::cout <<"\ntest result using linear fitter" << std::endl; fitter.Config().SetMinimizer("Linear"); f.SetParameters(p); ret = fitter.Fit(d, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Linear 2D Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"2D histogram linear fit"); // test fitting using TGraph2D ( chi2 will be larger since errors are 1) // should test with a TGraph2DErrors TGraph2D g2(h2); std::cout <<"\ntest using TGraph2D" << std::endl; ROOT::Fit::BinData d2; ROOT::Fit::FillData(d2,&g2,func); //g2.Dump(); std::cout << "data size from graph " << d2.Size() << std::endl; f2.SetParameters(p); fitter.Config().SetMinimizer("Minuit2"); ret = fitter.Fit(d2, f2); if (ret) fitter.Result().Print(std::cout); else { std::cout << " TGraph2D Fit Failed " << std::endl; return -1; } double chi2ref2 = fitter.Result().Chi2(); // compare with TGraph2D::Fit std::cout << "\n******************************\n\t TGraph::Fit Result \n" << std::endl; func->SetParameters(p); g2.Fit(func); std::cout <<"\ntest using TGraph2D and gradient function" << std::endl; f.SetParameters(p); ret = fitter.Fit(d2, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << " TGraph2D Grad Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref2,"TGraph2D chi2 fit"); std::cout <<"\ntest using TGraph2DErrors - error only in Z" << std::endl; TGraph2DErrors g2err(g2.GetN() ); // need to set error by hand since constructor from TH2 does not exist for (int i = 0; i < g2.GetN(); ++i) { double x = g2.GetX()[i]; double y = g2.GetY()[i]; g2err.SetPoint(i,x,y,g2.GetZ()[i]); g2err.SetPointError(i,0,0,h2->GetBinError(h2->FindBin(x,y) ) ); } func->SetParameters(p); // g2err.Fit(func); f.SetParameters(p); ROOT::Fit::BinData d3; ROOT::Fit::FillData(d3,&g2err,func); ret = fitter.Fit(d3, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << " TGraph2DErrors Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(), chi2ref,"TGraph2DErrors chi2 fit"); std::cout <<"\ntest using TGraph2DErrors - with error in X,Y,Z" << std::endl; for (int i = 0; i < g2err.GetN(); ++i) { double x = g2.GetX()[i]; double y = g2.GetY()[i]; g2err.SetPointError(i,0.5* h2->GetXaxis()->GetBinWidth(1),0.5*h2->GetXaxis()->GetBinWidth(1),h2->GetBinError(h2->FindBin(x,y) ) ); } std::cout << "\n******************************\n\t TGraph2DErrors::Fit Result \n" << std::endl; func->SetParameters(p); g2err.Fit(func); return iret; } int testUnBin1DFit() { int iret = 0; std::string fname("gausn"); TF1 * func = (TF1*)gROOT->GetFunction(fname.c_str()); TRandom3 rndm; int n = 100; ROOT::Fit::UnBinData d(n); for (int i = 0; i 0 std::cout << "set lower range to 0 for sigma " << std::endl; fitter.Config().ParSettings(2).SetLowerLimit(0); #ifdef DEBUG fitter.Config().MinimizerOptions().SetPrintLevel(3); #endif // double x[1]; x[0] = 0.; // std::cout << "fval " << f(x) << std::endl; // x[0] = 1.; std::cout << "fval " << f(x) << std::endl; //fitter.Config().SetMinimizer("Minuit2"); // fails with minuit (t.b. investigate) fitter.Config().SetMinimizer("Minuit2"); bool ret = fitter.Fit(d); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Unbinned Likelihood Fit Failed " << std::endl; iret |= 1; } double lref = fitter.Result().MinFcnValue(); std::cout << "\n\nRedo Fit using FUMILI2" << std::endl; f.SetParameters(p); fitter.Config().SetMinimizer("Fumili2"); // need to set function first (need to change this) fitter.SetFunction(f); fitter.Config().ParSettings(0).Fix(); //need to re-do it // set range in sigma sigma > 0 fitter.Config().ParSettings(2).SetLowerLimit(0); ret = fitter.Fit(d); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Unbinned Likelihood Fit using FUMILI2 Failed " << std::endl; iret |= 1; } iret |= compareResult(fitter.Result().MinFcnValue(), lref,"1D unbin FUMILI2 fit"); std::cout << "\n\nRedo Fit using FUMILI" << std::endl; f.SetParameters(p); fitter.Config().SetMinimizer("Fumili"); // fitter.Config().MinimizerOptions().SetPrintLevel(3); // need to set function first (need to change this) fitter.SetFunction(f); fitter.Config().ParSettings(0).Fix(); //need to re-do it // set range in sigma sigma > 0 fitter.Config().ParSettings(2).SetLowerLimit(0); ret = fitter.Fit(d); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Unbinned Likelihood Fit using FUMILI Failed " << std::endl; iret |= 1; } iret |= compareResult(fitter.Result().MinFcnValue(), lref,"1D unbin FUMILI fit"); return iret; } int testGraphFit() { int iret = 0; // simple test of fitting a Tgraph double x[5] = {1,2,3,4,5}; double y[5] = {2.1, 3.5, 6.5, 8.8, 9.5}; double ex[5] = {.3,.3,.3,.3,.3}; double ey[5] = {.5,.5,.5,.5,.5}; double eyl[5] = {.2,.2,.2,.2,.2}; double eyh[5] = {.8,.8,.8,.8,.8}; std::cout << "\n********************************************************\n"; std::cout << "Test simple fit of Tgraph of 5 points" << std::endl; std::cout << "\n********************************************************\n"; double p[2] = {1,1}; TF1 * func = new TF1("f","pol1",0,10); func->SetParameters(p); ROOT::Math::WrappedMultiTF1 wf(*func); // need to do that to avoid gradient calculation ROOT::Math::IParamMultiFunction & f = wf; f.SetParameters(p); ROOT::Fit::Fitter fitter; fitter.SetFunction(f); std::cout <<"\ntest TGraph (no errors) " << std::endl; TGraph gr(5, x,y); ROOT::Fit::BinData dgr; ROOT::Fit::FillData(dgr,&gr); //printData(dgr); f.SetParameters(p); bool ret = fitter.Fit(dgr, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Graph Fit Failed " << std::endl; return -1; } double chi2ref = fitter.Result().Chi2(); // compare with TGraph::Fit std::cout << "\n******************************\n\t TGraph::Fit Result \n" << std::endl; func->SetParameters(p); gr.Fit(func,"F"); // use Minuit iret |= compareResult(func->GetChisquare(),fitter.Result().Chi2(),"TGraph::Fit ",0.001); std::cout <<"\ntest TGraphErrors " << std::endl; TGraphErrors grer(5, x,y,ex,ey); ROOT::Fit::BinData dgrer; dgrer.Opt().fCoordErrors = true; ROOT::Fit::FillData(dgrer,&grer); //printData(dgrer); f.SetParameters(p); ret = fitter.Fit(dgrer, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Graph Fit Failed " << std::endl; return -1; } iret |= compareResult(fitter.Result().Chi2(),chi2ref,"TGraphErrors fit with coord errors",0.8); // compare with TGraph::Fit std::cout << "\n******************************\n\t TGraphErrors::Fit Result \n" << std::endl; func->SetParameters(p); grer.Fit(func,"F"); // use Minuit iret |= compareResult(func->GetChisquare(),fitter.Result().Chi2(),"TGraphErrors::Fit ",0.001); chi2ref = fitter.Result().Chi2(); std::cout <<"\ntest TGraphAsymmErrors " << std::endl; TGraphAsymmErrors graer(5, x,y,ex,ex,eyl, eyh); ROOT::Fit::BinData dgraer; // option error on coordinate and asymmetric on values dgraer.Opt().fCoordErrors = true; dgraer.Opt().fAsymErrors = true; ROOT::Fit::FillData(dgraer,&graer); //printData(dgraer); f.SetParameters(p); ret = fitter.Fit(dgraer, f); if (ret) fitter.Result().Print(std::cout); else { std::cout << "Chi2 Graph Fit Failed " << std::endl; return -1; } //iret |= compareResult(fitter.Result().Chi2(),chi2ref,"TGraphAsymmErrors fit ",0.5); // compare with TGraph::Fit std::cout << "\n******************************\n\t TGraphAsymmErrors::Fit Result \n" << std::endl; func->SetParameters(p); graer.Fit(func,"F"); // use Minuit iret |= compareResult(func->GetChisquare(),fitter.Result().Chi2(),"TGraphAsymmErrors::Fit ",0.001); return iret; } template int testFit(Test t, std::string name) { std::cout << name << "\n\t\t"; int iret = t(); std::cout << "\n" << name << ":\t\t"; if (iret == 0) std::cout << "OK" << std::endl; else std::cout << "Failed" << std::endl; return iret; } int main() { int iret = 0; iret |= testFit( testHisto1DFit, "Histogram1D Fit"); iret |= testFit( testHisto1DPolFit, "Histogram1D Polynomial Fit"); iret |= testFit( testHisto2DFit, "Histogram2D Gradient Fit"); iret |= testFit( testUnBin1DFit, "Unbin 1D Fit"); iret |= testFit( testGraphFit, "Graph 1D Fit"); std::cout << "\n******************************\n"; if (iret) std::cerr << "\n\t testFit FAILED !!!!!!!!!!!!!!!! \n"; else std::cout << "\n\t testFit all OK \n"; return iret; }