{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "48af628b",
   "metadata": {},
   "source": [
    "# rf312_multirangefit\n",
    "Multidimensional models: performing fits in multiple (disjoint) ranges in one or more dimensions\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:31 PM.</small></i>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "1ddaa538",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:10.629356Z",
     "iopub.status.busy": "2026-05-19T20:31:10.629241Z",
     "iopub.status.idle": "2026-05-19T20:31:11.592187Z",
     "shell.execute_reply": "2026-05-19T20:31:11.590991Z"
    }
   },
   "outputs": [],
   "source": [
    "import ROOT"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7d1220c",
   "metadata": {},
   "source": [
    "Create 2D pdf and data\n",
    "-------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d450e99f",
   "metadata": {},
   "source": [
    "Define observables x,y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "bbe0cf8d",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:11.593802Z",
     "iopub.status.busy": "2026-05-19T20:31:11.593646Z",
     "iopub.status.idle": "2026-05-19T20:31:11.754193Z",
     "shell.execute_reply": "2026-05-19T20:31:11.753063Z"
    }
   },
   "outputs": [],
   "source": [
    "x = ROOT.RooRealVar(\"x\", \"x\", -10, 10)\n",
    "y = ROOT.RooRealVar(\"y\", \"y\", -10, 10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3ad780a",
   "metadata": {},
   "source": [
    "Construct the signal pdf gauss(x)*gauss(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "00b64458",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:11.755710Z",
     "iopub.status.busy": "2026-05-19T20:31:11.755555Z",
     "iopub.status.idle": "2026-05-19T20:31:11.895750Z",
     "shell.execute_reply": "2026-05-19T20:31:11.895057Z"
    }
   },
   "outputs": [],
   "source": [
    "mx = ROOT.RooRealVar(\"mx\", \"mx\", 1, -10, 10)\n",
    "my = ROOT.RooRealVar(\"my\", \"my\", 1, -10, 10)\n",
    "\n",
    "gx = ROOT.RooGaussian(\"gx\", \"gx\", x, mx, 1.0)\n",
    "gy = ROOT.RooGaussian(\"gy\", \"gy\", y, my, 1.0)\n",
    "\n",
    "sig = ROOT.RooProdPdf(\"sig\", \"sig\", gx, gy)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c64809eb",
   "metadata": {},
   "source": [
    "Construct the background pdf (flat in x,y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c48184be",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:11.897537Z",
     "iopub.status.busy": "2026-05-19T20:31:11.897416Z",
     "iopub.status.idle": "2026-05-19T20:31:12.008499Z",
     "shell.execute_reply": "2026-05-19T20:31:12.007861Z"
    }
   },
   "outputs": [],
   "source": [
    "px = ROOT.RooPolynomial(\"px\", \"px\", x)\n",
    "py = ROOT.RooPolynomial(\"py\", \"py\", y)\n",
    "bkg = ROOT.RooProdPdf(\"bkg\", \"bkg\", px, py)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52f4cbea",
   "metadata": {},
   "source": [
    "Construct the composite model sig+bkg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "98a808d5",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:12.010250Z",
     "iopub.status.busy": "2026-05-19T20:31:12.010125Z",
     "iopub.status.idle": "2026-05-19T20:31:12.188470Z",
     "shell.execute_reply": "2026-05-19T20:31:12.187786Z"
    }
   },
   "outputs": [],
   "source": [
    "f = ROOT.RooRealVar(\"f\", \"f\", 0.0, 1.0)\n",
    "model = ROOT.RooAddPdf(\"model\", \"model\", [sig, bkg], [f])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3549582",
   "metadata": {},
   "source": [
    "Sample 10000 events in (x,y) from the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "39fbcd4e",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:12.190258Z",
     "iopub.status.busy": "2026-05-19T20:31:12.190131Z",
     "iopub.status.idle": "2026-05-19T20:31:12.344307Z",
     "shell.execute_reply": "2026-05-19T20:31:12.343651Z"
    }
   },
   "outputs": [],
   "source": [
    "modelData = model.generate({x, y}, 10000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4de56eb8",
   "metadata": {},
   "source": [
    "Define signal and sideband regions\n",
    "-------------------------------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76324a57",
   "metadata": {},
   "source": [
    "Construct the SideBand1,SideBand2, regions\n",
    "\n",
    "                   |\n",
    "     +-------------+-----------+\n",
    "     |             |           |\n",
    "     |    Side     |   Sig     |\n",
    "     |    Band1    |   nal     |\n",
    "     |             |           |\n",
    "   --+-------------+-----------+--\n",
    "     |                         |\n",
    "     |           Side          |\n",
    "     |           Band2         |\n",
    "     |                         |\n",
    "     +-------------+-----------+\n",
    "                   |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "058fa767",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:12.346128Z",
     "iopub.status.busy": "2026-05-19T20:31:12.346003Z",
     "iopub.status.idle": "2026-05-19T20:31:12.461884Z",
     "shell.execute_reply": "2026-05-19T20:31:12.461195Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#1] INFO:Eval -- RooRealVar::setRange(x) new range named 'SB1' created with bounds [-10,10]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(y) new range named 'SB1' created with bounds [-10,0]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(x) new range named 'SB2' created with bounds [-10,0]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(y) new range named 'SB2' created with bounds [0,10]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(x) new range named 'SIG' created with bounds [0,10]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(y) new range named 'SIG' created with bounds [0,10]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(x) new range named 'FULL' created with bounds [-10,10]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(y) new range named 'FULL' created with bounds [-10,10]\n"
     ]
    }
   ],
   "source": [
    "x.setRange(\"SB1\", -10, +10)\n",
    "y.setRange(\"SB1\", -10, 0)\n",
    "\n",
    "x.setRange(\"SB2\", -10, 0)\n",
    "y.setRange(\"SB2\", 0, +10)\n",
    "\n",
    "x.setRange(\"SIG\", 0, +10)\n",
    "y.setRange(\"SIG\", 0, +10)\n",
    "\n",
    "x.setRange(\"FULL\", -10, +10)\n",
    "y.setRange(\"FULL\", -10, +10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e186c5a0",
   "metadata": {},
   "source": [
    "Perform fits in individual sideband regions\n",
    "-------------------------------------------------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e36f71c",
   "metadata": {},
   "source": [
    "Perform fit in SideBand1 region (ROOT.RooAddPdf coefficients will be\n",
    "interpreted in full range)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "9f927e4e",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:12.463395Z",
     "iopub.status.busy": "2026-05-19T20:31:12.463259Z",
     "iopub.status.idle": "2026-05-19T20:31:12.667727Z",
     "shell.execute_reply": "2026-05-19T20:31:12.667056Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#1] INFO:Eval -- RooRealVar::setRange(x) new range named 'fit_nll_model_modelData' created with bounds [-10,10]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(y) new range named 'fit_nll_model_modelData' created with bounds [-10,0]\n",
      "[#1] INFO:Fitting -- RooAbsPdf::fitTo(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:Fitting -- Creation of NLL object took 1.39779 ms\n",
      "[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_model_modelData) Summation contains a RooNLLVar, using its error level\n",
      "[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only\n"
     ]
    }
   ],
   "source": [
    "r_sb1 = model.fitTo(modelData, Range=\"SB1\", Save=True, PrintLevel=-1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52dffbfb",
   "metadata": {},
   "source": [
    "Perform fit in SideBand2 region (ROOT.RooAddPdf coefficients will be\n",
    "interpreted in full range)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "21f54cb3",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:12.669462Z",
     "iopub.status.busy": "2026-05-19T20:31:12.669338Z",
     "iopub.status.idle": "2026-05-19T20:31:12.777648Z",
     "shell.execute_reply": "2026-05-19T20:31:12.776976Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#1] INFO:Fitting -- RooAbsPdf::fitTo(model) fixing normalization set for coefficient determination to observables in data\n",
      "[#1] INFO:Fitting -- Creation of NLL object took 647.203 μs\n",
      "[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_model_modelData) Summation contains a RooNLLVar, using its error level\n",
      "[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only\n"
     ]
    }
   ],
   "source": [
    "r_sb2 = model.fitTo(modelData, Range=\"SB2\", Save=True, PrintLevel=-1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a49350f",
   "metadata": {},
   "source": [
    "Perform fits in joint sideband regions\n",
    "-----------------------------------------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ca28ea6",
   "metadata": {},
   "source": [
    "Now perform fit to joint 'L-shaped' sideband region 'SB1|SB2'\n",
    "(ROOT.RooAddPdf coefficients will be interpreted in full range)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "c777086e",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:12.779281Z",
     "iopub.status.busy": "2026-05-19T20:31:12.779161Z",
     "iopub.status.idle": "2026-05-19T20:31:12.892458Z",
     "shell.execute_reply": "2026-05-19T20:31:12.891860Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#1] INFO:Eval -- RooRealVar::setRange(x) new range named 'fit_nll_model_modelData_SB1' created with bounds [-10,10]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(y) new range named 'fit_nll_model_modelData_SB1' created with bounds [-10,0]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(x) new range named 'fit_nll_model_modelData_SB2' created with bounds [-10,0]\n",
      "[#1] INFO:Eval -- RooRealVar::setRange(y) new range named 'fit_nll_model_modelData_SB2' created with bounds [0,10]\n",
      "[#1] INFO:Fitting -- RooAbsPdf::fitTo(model) fixing normalization set for coefficient determination to observables in data\n",
      "[#1] INFO:Fitting -- Creation of NLL object took 941.023 μs\n",
      "[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_model_modelData) Summation contains a RooNLLVar, using its error level\n",
      "[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only\n"
     ]
    }
   ],
   "source": [
    "r_sb12 = model.fitTo(modelData, Range=\"SB1,SB2\", Save=True, PrintLevel=-1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4cd7126",
   "metadata": {},
   "source": [
    "Print results for comparison"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e9e9bb12",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:31:12.894007Z",
     "iopub.status.busy": "2026-05-19T20:31:12.893884Z",
     "iopub.status.idle": "2026-05-19T20:31:13.003588Z",
     "shell.execute_reply": "2026-05-19T20:31:13.002937Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "  RooFitResult: minimized FCN value: 16261.4, estimated distance to minimum: 5.06415e-07\n",
      "                covariance matrix quality: Full, accurate covariance matrix\n",
      "                Status : MINIMIZE=0 HESSE=0 \n",
      "\n",
      "    Floating Parameter    FinalValue +/-  Error   \n",
      "  --------------------  --------------------------\n",
      "                     f    5.1135e-01 +/-  3.58e-02\n",
      "                    mx    9.8740e-01 +/-  4.03e-02\n",
      "                    my    9.9305e-01 +/-  9.39e-02\n",
      "\n",
      "\n",
      "  RooFitResult: minimized FCN value: 7578.28, estimated distance to minimum: 3.07865e-06\n",
      "                covariance matrix quality: Full, accurate covariance matrix\n",
      "                Status : MINIMIZE=0 HESSE=0 \n",
      "\n",
      "    Floating Parameter    FinalValue +/-  Error   \n",
      "  --------------------  --------------------------\n",
      "                     f    5.4586e-01 +/-  4.46e-02\n",
      "                    mx    1.1276e+00 +/-  1.10e-01\n",
      "                    my    9.6462e-01 +/-  5.60e-02\n",
      "\n",
      "\n",
      "  RooFitResult: minimized FCN value: 27252.6, estimated distance to minimum: 2.25202e-06\n",
      "                covariance matrix quality: Full, accurate covariance matrix\n",
      "                Status : MINIMIZE=0 HESSE=0 \n",
      "\n",
      "    Floating Parameter    FinalValue +/-  Error   \n",
      "  --------------------  --------------------------\n",
      "                     f    5.0082e-01 +/-  1.29e-02\n",
      "                    mx    1.0100e+00 +/-  3.26e-02\n",
      "                    my    9.6348e-01 +/-  3.31e-02\n",
      "\n"
     ]
    }
   ],
   "source": [
    "r_sb1.Print()\n",
    "r_sb2.Print()\n",
    "r_sb12.Print()"
   ]
  }
 ],
 "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
}
