{ "cells": [ { "cell_type": "markdown", "id": "5f920511", "metadata": {}, "source": [ "# TwoHistoFit2D\n", "Example to fit two histograms at the same time.\n", "\n", "\n", "\n", "\n", "**Author:** Rene Brun \n", "This notebook tutorial was automatically generated with ROOTBOOK-izer from the macro found in the ROOT repository on Tuesday, May 19, 2026 at 08:25 PM." ] }, { "cell_type": "code", "execution_count": 1, "id": "4761c675", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:21.176479Z", "iopub.status.busy": "2026-05-19T20:25:21.176340Z", "iopub.status.idle": "2026-05-19T20:25:21.507050Z", "shell.execute_reply": "2026-05-19T20:25:21.503513Z" } }, "outputs": [], "source": [ "std::vector > coords;\n", "std::vector values;\n", "std::vector errors;\n", "\n", "TRandom3 rndm;" ] }, { "cell_type": "markdown", "id": "c04ca417", "metadata": {}, "source": [ " Definition of a helper function: " ] }, { "cell_type": "code", "execution_count": 2, "id": "99540d95", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:21.509064Z", "iopub.status.busy": "2026-05-19T20:25:21.508938Z", "iopub.status.idle": "2026-05-19T20:25:21.513168Z", "shell.execute_reply": "2026-05-19T20:25:21.512574Z" } }, "outputs": [], "source": [ "%%cpp -d\n", "\n", "#include \"TH2D.h\"\n", "#include \"TF2.h\"\n", "#include \"TCanvas.h\"\n", "#include \"TStyle.h\"\n", "#include \"TRandom3.h\"\n", "#include \"TVirtualFitter.h\"\n", "#include \"TList.h\"\n", "\n", "#include \n", "#include \n", "#include \n", "\n", "double gauss2D(double *x, double *par) {\n", " double z1 = double((x[0]-par[1])/par[2]);\n", " double z2 = double((x[1]-par[3])/par[4]);\n", " return par[0]*exp(-0.5*(z1*z1+z2*z2));\n", "}" ] }, { "cell_type": "markdown", "id": "9f3c3a25", "metadata": {}, "source": [ " Definition of a helper function: " ] }, { "cell_type": "code", "execution_count": 3, "id": "626d56c5", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:21.514592Z", "iopub.status.busy": "2026-05-19T20:25:21.514479Z", "iopub.status.idle": "2026-05-19T20:25:21.517002Z", "shell.execute_reply": "2026-05-19T20:25:21.516427Z" } }, "outputs": [], "source": [ "%%cpp -d\n", "double my2Dfunc(double *x, double *par) {\n", " double *p1 = &par[0];\n", " double *p2 = &par[5];\n", " return gauss2D(x,p1) + gauss2D(x,p2);\n", "}" ] }, { "cell_type": "markdown", "id": "6cb6a12d", "metadata": {}, "source": [ " data need to be globals to be visible by fcn\n", " " ] }, { "cell_type": "code", "execution_count": 4, "id": "db018eef", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:21.518391Z", "iopub.status.busy": "2026-05-19T20:25:21.518280Z", "iopub.status.idle": "2026-05-19T20:25:21.522425Z", "shell.execute_reply": "2026-05-19T20:25:21.521858Z" } }, "outputs": [], "source": [ "%%cpp -d\n", "void myFcn(int & /*nPar*/, double * /*grad*/ , double &fval, double *p, int /*iflag */ )\n", "{\n", " int n = coords.size();\n", " double chi2 = 0;\n", " double tmp,x[2];\n", " for (int i = 0; i Fill(x,y);\n", "\n", " }\n", "}" ] }, { "cell_type": "markdown", "id": "62cd5cbc", "metadata": {}, "source": [ " Arguments are defined. " ] }, { "cell_type": "code", "execution_count": 6, "id": "a9c5bc11", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:21.531339Z", "iopub.status.busy": "2026-05-19T20:25:21.531223Z", "iopub.status.idle": "2026-05-19T20:25:21.743327Z", "shell.execute_reply": "2026-05-19T20:25:21.742955Z" } }, "outputs": [], "source": [ "bool global = true;" ] }, { "cell_type": "markdown", "id": "e1596841", "metadata": {}, "source": [ "create two histograms" ] }, { "cell_type": "code", "execution_count": 7, "id": "9f09f794", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:21.753360Z", "iopub.status.busy": "2026-05-19T20:25:21.753228Z", "iopub.status.idle": "2026-05-19T20:25:21.957793Z", "shell.execute_reply": "2026-05-19T20:25:21.957150Z" } }, "outputs": [], "source": [ " int nbx1 = 50;\n", " int nby1 = 50;\n", " int nbx2 = 50;\n", " int nby2 = 50;\n", " double xlow1 = 0.;\n", " double ylow1 = 0.;\n", " double xup1 = 10.;\n", " double yup1 = 10.;\n", " double xlow2 = 5.;\n", " double ylow2 = 5.;\n", " double xup2 = 20.;\n", " double yup2 = 20.;\n", "\n", " TH2D * h1 = new TH2D(\"h1\",\"core\",nbx1,xlow1,xup1,nby1,ylow1,yup1);\n", " TH2D * h2 = new TH2D(\"h2\",\"tails\",nbx2,xlow2,xup2,nby2,ylow2,yup2);\n", "\n", " double iniParams[10] = { 100, 6., 2., 7., 3, 100, 12., 3., 11., 2. };" ] }, { "cell_type": "markdown", "id": "a40eb2dc", "metadata": {}, "source": [ "create fit function" ] }, { "cell_type": "code", "execution_count": 8, "id": "1665b80e", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:21.959838Z", "iopub.status.busy": "2026-05-19T20:25:21.959715Z", "iopub.status.idle": "2026-05-19T20:25:22.166136Z", "shell.execute_reply": "2026-05-19T20:25:22.165578Z" } }, "outputs": [], "source": [ " TF2 * func = new TF2(\"func\",my2Dfunc,xlow2,xup2,ylow2,yup2, 10);\n", " func->SetParameters(iniParams);" ] }, { "cell_type": "markdown", "id": "89fda778", "metadata": {}, "source": [ "fill Histos" ] }, { "cell_type": "code", "execution_count": 9, "id": "f87b875e", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:22.168245Z", "iopub.status.busy": "2026-05-19T20:25:22.168120Z", "iopub.status.idle": "2026-05-19T20:25:22.374571Z", "shell.execute_reply": "2026-05-19T20:25:22.373954Z" } }, "outputs": [], "source": [ " int n1 = 50000;\n", " int n2 = 50000;" ] }, { "cell_type": "markdown", "id": "7c976ba7", "metadata": {}, "source": [ "h1->FillRandom(\"func\", n1);\n", "h2->FillRandom(\"func\",n2);" ] }, { "cell_type": "code", "execution_count": 10, "id": "3b77c82c", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:22.376661Z", "iopub.status.busy": "2026-05-19T20:25:22.376508Z", "iopub.status.idle": "2026-05-19T20:25:22.584165Z", "shell.execute_reply": "2026-05-19T20:25:22.582925Z" } }, "outputs": [], "source": [ " FillHisto(h1,n1,iniParams);\n", " FillHisto(h2,n2,iniParams);" ] }, { "cell_type": "markdown", "id": "4b231a59", "metadata": {}, "source": [ "scale histograms to same heights (for fitting)" ] }, { "cell_type": "code", "execution_count": 11, "id": "ee05e595", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:22.585956Z", "iopub.status.busy": "2026-05-19T20:25:22.585837Z", "iopub.status.idle": "2026-05-19T20:25:22.788303Z", "shell.execute_reply": "2026-05-19T20:25:22.787619Z" } }, "outputs": [], "source": [ " double dx1 = (xup1-xlow1)/double(nbx1);\n", " double dy1 = (yup1-ylow1)/double(nby1);\n", " double dx2 = (xup2-xlow2)/double(nbx2);\n", " double dy2 = (yup2-ylow2)/double(nby2);" ] }, { "cell_type": "markdown", "id": "4da826d4", "metadata": {}, "source": [ "h1->Sumw2();\n", "h1->Scale( 1.0 / ( n1 * dx1 * dy1 ) );\n", "scale histo 2 to scale of 1" ] }, { "cell_type": "code", "execution_count": 12, "id": "8ab487fd", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:22.790585Z", "iopub.status.busy": "2026-05-19T20:25:22.790463Z", "iopub.status.idle": "2026-05-19T20:25:23.105491Z", "shell.execute_reply": "2026-05-19T20:25:23.104840Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Do global fit\n", " PARAMETER DEFINITIONS:\n", " NO. NAME VALUE STEP SIZE LIMITS\n", " 1 p0 1.00000e+02 1.00000e-02 no limits\n", " 2 p1 6.00000e+00 1.00000e-02 no limits\n", " 3 p2 2.00000e+00 1.00000e-02 no limits\n", " 4 p3 7.00000e+00 1.00000e-02 no limits\n", " 5 p4 3.00000e+00 1.00000e-02 no limits\n", " 6 p5 1.00000e+02 1.00000e-02 no limits\n", " 7 p6 1.20000e+01 1.00000e-02 no limits\n", " 8 p7 3.00000e+00 1.00000e-02 no limits\n", " 9 p8 1.10000e+01 1.00000e-02 no limits\n", " 10 p9 2.00000e+00 1.00000e-02 no limits\n", " **********\n", " ** 1 **SET PRINT 0 16.85\n", " **********\n", " **********\n", " ** 2 **MIGRAD 5000 0.01\n", " **********\n", " MIGRAD MINIMIZATION HAS CONVERGED.\n", " FCN=4015.63 FROM MIGRAD STATUS=CONVERGED 525 CALLS 526 TOTAL\n", " EDM=7.64859e-07 STRATEGY= 1 ERROR MATRIX UNCERTAINTY 4.8 per cent\n", " EXT PARAMETER STEP FIRST \n", " NO. NAME VALUE ERROR SIZE DERIVATIVE \n", " 1 p0 2.55114e+01 2.22488e-01 1.18177e-03 1.29662e-03\n", " 2 p1 6.03551e+00 1.56999e-02 1.78147e-04 5.19787e-02\n", " 3 p2 1.95953e+00 1.34972e-02 1.02338e-04 -2.33234e-02\n", " 4 p3 7.09821e+00 3.32869e-02 2.39024e-04 2.42664e-02\n", " 5 p4 2.94271e+00 2.42010e-02 -1.88552e-04 2.78521e-03\n", " 6 p5 2.63145e+01 2.69272e-01 -2.31447e-03 -2.60063e-03\n", " 7 p6 1.19850e+01 3.51596e-02 4.24095e-04 -3.93610e-02\n", " 8 p7 2.90086e+00 2.64547e-02 8.06258e-05 -5.19642e-03\n", " 9 p8 1.09762e+01 1.47334e-02 -6.74372e-05 -1.09628e-02\n", " 10 p9 1.95760e+00 1.14466e-02 2.85421e-05 -1.15592e-01\n", "Chi2 Fit = 4015.63 ndf = 3921 3921\n" ] } ], "source": [ " h2->Sumw2();\n", " h2->Scale( ( double(n1) * dx1 * dy1 ) / ( double(n2) * dx2 * dy2 ) );\n", "\n", "\n", " if (global) {\n", " // fill data structure for fit (coordinates + values + errors)\n", " std::cout << \"Do global fit\" << std::endl;\n", " // fit now all the function together\n", "\n", " // fill data structure for fit (coordinates + values + errors)\n", " TAxis *xaxis1 = h1->GetXaxis();\n", " TAxis *yaxis1 = h1->GetYaxis();\n", " TAxis *xaxis2 = h2->GetXaxis();\n", " TAxis *yaxis2 = h2->GetYaxis();\n", "\n", " int nbinX1 = h1->GetNbinsX();\n", " int nbinY1 = h1->GetNbinsY();\n", " int nbinX2 = h2->GetNbinsX();\n", " int nbinY2 = h2->GetNbinsY();\n", "\n", " /// reset data structure\n", " coords = std::vector >();\n", " values = std::vector();\n", " errors = std::vector();\n", "\n", "\n", " for (int ix = 1; ix <= nbinX1; ++ix) {\n", " for (int iy = 1; iy <= nbinY1; ++iy) {\n", " if ( h1->GetBinContent(ix,iy) > 0 ) {\n", " coords.push_back( std::make_pair(xaxis1->GetBinCenter(ix), yaxis1->GetBinCenter(iy) ) );\n", " values.push_back( h1->GetBinContent(ix,iy) );\n", " errors.push_back( h1->GetBinError(ix,iy) );\n", " }\n", " }\n", " }\n", " for (int ix = 1; ix <= nbinX2; ++ix) {\n", " for (int iy = 1; iy <= nbinY2; ++iy) {\n", " if ( h2->GetBinContent(ix,iy) > 0 ) {\n", " coords.push_back( std::make_pair(xaxis2->GetBinCenter(ix), yaxis2->GetBinCenter(iy) ) );\n", " values.push_back( h2->GetBinContent(ix,iy) );\n", " errors.push_back( h2->GetBinError(ix,iy) );\n", " }\n", " }\n", " }\n", "\n", " TVirtualFitter::SetDefaultFitter(\"Minuit\");\n", " TVirtualFitter * minuit = TVirtualFitter::Fitter(nullptr,10);\n", " for (int i = 0; i < 10; ++i) {\n", " minuit->SetParameter(i, func->GetParName(i), func->GetParameter(i), 0.01, 0,0);\n", " }\n", " minuit->SetFCN(myFcn);\n", "\n", " double arglist[100];\n", " arglist[0] = 0;\n", " // set print level\n", " minuit->ExecuteCommand(\"SET PRINT\",arglist,2);\n", "\n", "// minimize\n", " arglist[0] = 5000; // number of function calls\n", " arglist[1] = 0.01; // tolerance\n", " minuit->ExecuteCommand(\"MIGRAD\",arglist,2);\n", "\n", " //get result\n", " double minParams[10];\n", " double parErrors[10];\n", " for (int i = 0; i < 10; ++i) {\n", " minParams[i] = minuit->GetParameter(i);\n", " parErrors[i] = minuit->GetParError(i);\n", " }\n", " double chi2, edm, errdef;\n", " int nvpar, nparx;\n", " minuit->GetStats(chi2,edm,errdef,nvpar,nparx);\n", "\n", " func->SetParameters(minParams);\n", " func->SetParErrors(parErrors);\n", " func->SetChisquare(chi2);\n", " int ndf = coords.size()-nvpar;\n", " func->SetNDF(ndf);\n", "\n", " std::cout << \"Chi2 Fit = \" << chi2 << \" ndf = \" << ndf << \" \" << func->GetNDF() << std::endl;\n", "\n", " // add to list of functions\n", " h1->GetListOfFunctions()->Add(func);\n", " h2->GetListOfFunctions()->Add(func);\n", " }\n", " else {\n", " // fit independently\n", " h1->Fit(func);\n", " h2->Fit(func);\n", " }" ] }, { "cell_type": "markdown", "id": "a7ba45a8", "metadata": {}, "source": [ "Create a new canvas." ] }, { "cell_type": "code", "execution_count": 13, "id": "e8b8d699", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:23.107068Z", "iopub.status.busy": "2026-05-19T20:25:23.106953Z", "iopub.status.idle": "2026-05-19T20:25:23.458544Z", "shell.execute_reply": "2026-05-19T20:25:23.458128Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ " TCanvas * c1 = new TCanvas(\"c1\",\"Two HIstogram Fit example\",100,10,900,800);\n", " c1->Divide(2,2);\n", " gStyle->SetOptFit();\n", " gStyle->SetStatY(0.6);\n", "\n", " c1->cd(1);\n", " h1->Draw();\n", " func->SetRange(xlow1,ylow1,xup1,yup1);\n", " func->DrawCopy(\"cont1 same\");\n", " c1->cd(2);\n", " h1->Draw(\"lego\");\n", " func->DrawCopy(\"surf1 same\");\n", " c1->cd(3);\n", " func->SetRange(xlow2,ylow2,xup2,yup2);\n", " h2->Draw();\n", " func->DrawCopy(\"cont1 same\");\n", " c1->cd(4);\n", " h2->Draw(\"lego\");\n", " gPad->SetLogz();\n", " func->Draw(\"surf1 same\");\n", "\n", " return 0;" ] }, { "cell_type": "markdown", "id": "a15569a6", "metadata": {}, "source": [ "Draw all canvases " ] }, { "cell_type": "code", "execution_count": 14, "id": "72f33095", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:25:23.470090Z", "iopub.status.busy": "2026-05-19T20:25:23.469956Z", "iopub.status.idle": "2026-05-19T20:25:23.688139Z", "shell.execute_reply": "2026-05-19T20:25:23.687506Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "gROOT->GetListOfCanvases()->Draw()" ] } ], "metadata": { "kernelspec": { "display_name": "ROOT C++", "language": "c++", "name": "root" }, "language_info": { "codemirror_mode": "text/x-c++src", "file_extension": ".C", "mimetype": " text/x-c++src", "name": "c++" } }, "nbformat": 4, "nbformat_minor": 5 }