{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ed88257f",
   "metadata": {},
   "source": [
    "# rf602_chi2fit\n",
    "'LIKELIHOOD AND MINIMIZATION' RooFit tutorial macro #602\n",
    "\n",
    "Setting up a chi^2 fit to a binned dataset\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "**Author:**  Clemens Lange, Wouter Verkerke (C version)  \n",
    "<i><small>This notebook tutorial was automatically generated with <a href= \"https://github.com/root-project/root/blob/master/documentation/doxygen/converttonotebook.py\">ROOTBOOK-izer</a> from the macro found in the ROOT repository  on Tuesday, May 19, 2026 at 08:32 PM.</small></i>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0109b616",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:00.827309Z",
     "iopub.status.busy": "2026-05-19T20:33:00.827195Z",
     "iopub.status.idle": "2026-05-19T20:33:01.800020Z",
     "shell.execute_reply": "2026-05-19T20:33:01.799314Z"
    }
   },
   "outputs": [],
   "source": [
    "import ROOT"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37b108dc",
   "metadata": {},
   "source": [
    "Set up model\n",
    "---------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22c6c3ed",
   "metadata": {},
   "source": [
    "Declare observable x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d37f7e43",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:01.802359Z",
     "iopub.status.busy": "2026-05-19T20:33:01.802216Z",
     "iopub.status.idle": "2026-05-19T20:33:01.963659Z",
     "shell.execute_reply": "2026-05-19T20:33:01.962879Z"
    }
   },
   "outputs": [],
   "source": [
    "x = ROOT.RooRealVar(\"x\", \"x\", 0, 10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c91c1643",
   "metadata": {},
   "source": [
    "Create two Gaussian PDFs g1(x,mean1,sigma) anf g2(x,mean2,sigma) and\n",
    "their parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7b20a2f7",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:01.965772Z",
     "iopub.status.busy": "2026-05-19T20:33:01.965638Z",
     "iopub.status.idle": "2026-05-19T20:33:02.093150Z",
     "shell.execute_reply": "2026-05-19T20:33:02.092392Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#0] WARNING:InputArguments -- The parameter 'sigma1' with range [-inf, inf] of the RooGaussian 'sig1' exceeds the safe range of (0, inf). Advise to limit its range.\n",
      "[#0] WARNING:InputArguments -- The parameter 'sigma2' with range [-inf, inf] of the RooGaussian 'sig2' exceeds the safe range of (0, inf). Advise to limit its range.\n"
     ]
    }
   ],
   "source": [
    "mean = ROOT.RooRealVar(\"mean\", \"mean of gaussians\", 5)\n",
    "sigma1 = ROOT.RooRealVar(\"sigma1\", \"width of gaussians\", 0.5)\n",
    "sigma2 = ROOT.RooRealVar(\"sigma2\", \"width of gaussians\", 1)\n",
    "\n",
    "sig1 = ROOT.RooGaussian(\"sig1\", \"Signal component 1\", x, mean, sigma1)\n",
    "sig2 = ROOT.RooGaussian(\"sig2\", \"Signal component 2\", x, mean, sigma2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30846204",
   "metadata": {},
   "source": [
    "Build Chebychev polynomial p.d.f."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c317f3b6",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:02.095057Z",
     "iopub.status.busy": "2026-05-19T20:33:02.094931Z",
     "iopub.status.idle": "2026-05-19T20:33:02.273501Z",
     "shell.execute_reply": "2026-05-19T20:33:02.272745Z"
    }
   },
   "outputs": [],
   "source": [
    "a0 = ROOT.RooRealVar(\"a0\", \"a0\", 0.5, 0.0, 1.0)\n",
    "a1 = ROOT.RooRealVar(\"a1\", \"a1\", 0.2, 0.0, 1.0)\n",
    "bkg = ROOT.RooChebychev(\"bkg\", \"Background\", x, [a0, a1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5e6a99e",
   "metadata": {},
   "source": [
    "Sum the signal components into a composite signal p.d.f."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0ed1ebf7",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:02.275560Z",
     "iopub.status.busy": "2026-05-19T20:33:02.275431Z",
     "iopub.status.idle": "2026-05-19T20:33:02.388203Z",
     "shell.execute_reply": "2026-05-19T20:33:02.387502Z"
    }
   },
   "outputs": [],
   "source": [
    "sig1frac = ROOT.RooRealVar(\"sig1frac\", \"fraction of component 1 in signal\", 0.8, 0.0, 1.0)\n",
    "sig = ROOT.RooAddPdf(\"sig\", \"Signal\", [sig1, sig2], [sig1frac])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2592c07f",
   "metadata": {},
   "source": [
    "Sum the composite signal and background"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e1954cda",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:02.390388Z",
     "iopub.status.busy": "2026-05-19T20:33:02.390261Z",
     "iopub.status.idle": "2026-05-19T20:33:02.494245Z",
     "shell.execute_reply": "2026-05-19T20:33:02.493465Z"
    }
   },
   "outputs": [],
   "source": [
    "bkgfrac = ROOT.RooRealVar(\"bkgfrac\", \"fraction of background\", 0.5, 0.0, 1.0)\n",
    "model = ROOT.RooAddPdf(\"model\", \"g1+g2+a\", [bkg, sig], [bkgfrac])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "754bfa53",
   "metadata": {},
   "source": [
    "Create biuned dataset\n",
    "-----------------------------------------"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c4fff7de",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:02.496283Z",
     "iopub.status.busy": "2026-05-19T20:33:02.496159Z",
     "iopub.status.idle": "2026-05-19T20:33:02.651233Z",
     "shell.execute_reply": "2026-05-19T20:33:02.650811Z"
    }
   },
   "outputs": [],
   "source": [
    "d = model.generate({x}, 10000)\n",
    "dh = d.binnedClone()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39b2b506",
   "metadata": {},
   "source": [
    "Construct a chi^2 of the data and the model.\n",
    "When a p.d.f. is used in a chi^2 fit, probability density scaled\n",
    "by the number of events in the dataset to obtain the fit function\n",
    "If model is an extended p.d.f, expected number events is used\n",
    "instead of the observed number of events."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "27697014",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:02.666368Z",
     "iopub.status.busy": "2026-05-19T20:33:02.666223Z",
     "iopub.status.idle": "2026-05-19T20:33:02.845454Z",
     "shell.execute_reply": "2026-05-19T20:33:02.844890Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#1] INFO:Fitting -- createChi2(model) fixing normalization set for coefficient determination to observables in data\n",
      "[#1] INFO:Fitting -- using generic CPU library compiled with no vectorizations\n",
      "[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only\n",
      "Minuit2Minimizer: Minimize with max-calls 2000 convergence for edm < 1 strategy 1\n",
      "Minuit2Minimizer : Valid minimum - status = 0\n",
      "FVAL  = 104.639633447530315\n",
      "Edm   = 0.000778057066726829108\n",
      "Nfcn  = 70\n",
      "a0\t  = 0.501526\t +/-  0.0229096\t(limited)\n",
      "a1\t  = 0.158456\t +/-  0.0368354\t(limited)\n",
      "bkgfrac\t  = 0.506609\t +/-  0.011349\t(limited)\n",
      "sig1frac\t  = 0.815448\t +/-  0.0373695\t(limited)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Info in <Minuit2>: MnSeedGenerator Computing seed using NumericalGradient calculator\n",
      "Info in <Minuit2>: MnSeedGenerator Evaluated function and gradient in 151.389 μs\n",
      "Info in <Minuit2>: MnSeedGenerator Initial state: FCN =       106.1754789 Edm =       1.260070587 NCalls =     17\n",
      "Info in <Minuit2>: MnSeedGenerator Initial state  \n",
      "  Minimum value : 106.1754789\n",
      "  Edm           : 1.260070587\n",
      "  Internal parameters:\t[                0    -0.6435011088                0     0.6435011088]\t\n",
      "  Internal gradient  :\t[     -9.229193845      35.69317399      24.70460566      9.713828671]\t\n",
      "  Internal covariance matrix:\n",
      "[[   0.0021104285              0              0              0]\n",
      " [              0   0.0034850852              0              0]\n",
      " [              0              0   0.0001669053              0]\n",
      " [              0              0              0   0.0033769849]]]\n",
      "Info in <Minuit2>: VariableMetricBuilder Start iterating until Edm is < 0.002 with call limit = 2000\n",
      "Info in <Minuit2>: VariableMetricBuilder    0 - FCN =       106.1754789 Edm =       1.260070587 NCalls =     17\n",
      "Info in <Minuit2>: VariableMetricBuilder    1 - FCN =       105.1128131 Edm =     0.08526485559 NCalls =     27\n",
      "Info in <Minuit2>: VariableMetricBuilder    2 - FCN =         104.86813 Edm =      0.1538210631 NCalls =     37\n",
      "Info in <Minuit2>: VariableMetricBuilder    3 - FCN =       104.6396334 Edm =   0.0006219311323 NCalls =     47\n",
      "Info in <Minuit2>: MnHesse Done after 60.31 μs\n",
      "Info in <Minuit2>: VariableMetricBuilder After Hessian\n",
      "Info in <Minuit2>: VariableMetricBuilder    4 - FCN =       104.6396334 Edm =   0.0007780570667 NCalls =     70\n",
      "Info in <Minuit2>: VariableMetricBuilder Stop iterating after 198.371 μs\n",
      "Info in <Minuit2>: Minuit2Minimizer::Hesse Using max-calls 2000\n",
      "Info in <Minuit2>: MnHesse Done after 35.83 μs\n",
      "Info in <Minuit2>: Minuit2Minimizer::Hesse Hesse is valid - matrix is accurate\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<cppyy.gbl.RooFitResult object at 0x(nil)>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ll = ROOT.RooLinkedList()\n",
    "model.chi2FitTo(dh, ll)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0df68678",
   "metadata": {},
   "source": [
    "NB: It is also possible to fit a ROOT.RooAbsReal function to a ROOT.RooDataHist\n",
    "using chi2FitTo()."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07529da5",
   "metadata": {},
   "source": [
    "Note that entries with zero bins are _not_ allowed\n",
    "for a proper chi^2 calculation and will give error\n",
    "messages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "ee02940e",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:02.847626Z",
     "iopub.status.busy": "2026-05-19T20:33:02.847484Z",
     "iopub.status.idle": "2026-05-19T20:33:02.997536Z",
     "shell.execute_reply": "2026-05-19T20:33:02.996975Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#1] INFO:Fitting -- createChi2(model) fixing normalization set for coefficient determination to observables in data\n",
      "90.86495991422795\n"
     ]
    }
   ],
   "source": [
    "dsmall = d.reduce(ROOT.RooFit.EventRange(1, 100))\n",
    "dhsmall = dsmall.binnedClone()\n",
    "chi2_lowstat = model.createChi2(dhsmall)\n",
    "print(chi2_lowstat.getVal())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37e80560",
   "metadata": {},
   "source": [
    "Draw all canvases "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "58c96639",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:02.999565Z",
     "iopub.status.busy": "2026-05-19T20:33:02.999437Z",
     "iopub.status.idle": "2026-05-19T20:33:03.106989Z",
     "shell.execute_reply": "2026-05-19T20:33:03.106389Z"
    }
   },
   "outputs": [],
   "source": [
    "from ROOT import gROOT \n",
    "gROOT.GetListOfCanvases().Draw()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
