{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ecec8a63",
   "metadata": {},
   "source": [
    "# rf207_comptools\n",
    "'ADDITION AND CONVOLUTION' RooFit tutorial macro #207\n",
    "Tools and utilities for manipulation of composite objects\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:30 PM.</small></i>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "7b6b4585",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:03.544988Z",
     "iopub.status.busy": "2026-05-19T20:30:03.544872Z",
     "iopub.status.idle": "2026-05-19T20:30:04.502794Z",
     "shell.execute_reply": "2026-05-19T20:30:04.502064Z"
    }
   },
   "outputs": [],
   "source": [
    "import ROOT"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4dd56cb5",
   "metadata": {},
   "source": [
    "Set up composite pdf dataset\n",
    "--------------------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b2565c7a",
   "metadata": {},
   "source": [
    "Declare observable x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "599fd1be",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:04.504878Z",
     "iopub.status.busy": "2026-05-19T20:30:04.504737Z",
     "iopub.status.idle": "2026-05-19T20:30:04.667482Z",
     "shell.execute_reply": "2026-05-19T20:30:04.666782Z"
    }
   },
   "outputs": [],
   "source": [
    "x = ROOT.RooRealVar(\"x\", \"x\", 0, 10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "071f93fe",
   "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": "b2475085",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:04.669570Z",
     "iopub.status.busy": "2026-05-19T20:30:04.669441Z",
     "iopub.status.idle": "2026-05-19T20:30:04.797189Z",
     "shell.execute_reply": "2026-05-19T20:30:04.796420Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#0] WARNING:InputArguments -- The parameter 'sigma' with range [-inf, inf] of the RooGaussian 'sig' exceeds the safe range of (0, inf). Advise to limit its range.\n"
     ]
    }
   ],
   "source": [
    "mean = ROOT.RooRealVar(\"mean\", \"mean of gaussians\", 5)\n",
    "sigma = ROOT.RooRealVar(\"sigma\", \"width of gaussians\", 0.5)\n",
    "sig = ROOT.RooGaussian(\"sig\", \"Signal component 1\", x, mean, sigma)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "67ce40a4",
   "metadata": {},
   "source": [
    "Build Chebychev polynomial p.d.f."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "6c1d27c2",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:04.798669Z",
     "iopub.status.busy": "2026-05-19T20:30:04.798523Z",
     "iopub.status.idle": "2026-05-19T20:30:04.985680Z",
     "shell.execute_reply": "2026-05-19T20:30:04.980328Z"
    }
   },
   "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",
    "bkg1 = ROOT.RooChebychev(\"bkg1\", \"Background 1\", x, [a0, a1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c66d4d6",
   "metadata": {},
   "source": [
    "Build expontential pdf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ba01823a",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:04.987220Z",
     "iopub.status.busy": "2026-05-19T20:30:04.987089Z",
     "iopub.status.idle": "2026-05-19T20:30:05.105901Z",
     "shell.execute_reply": "2026-05-19T20:30:05.098001Z"
    }
   },
   "outputs": [],
   "source": [
    "alpha = ROOT.RooRealVar(\"alpha\", \"alpha\", -1)\n",
    "bkg2 = ROOT.RooExponential(\"bkg2\", \"Background 2\", x, alpha)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "815ad51a",
   "metadata": {},
   "source": [
    "Sum the background components into a composite background p.d.f."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "9b5e0dbf",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:05.112992Z",
     "iopub.status.busy": "2026-05-19T20:30:05.112851Z",
     "iopub.status.idle": "2026-05-19T20:30:05.225386Z",
     "shell.execute_reply": "2026-05-19T20:30:05.224860Z"
    }
   },
   "outputs": [],
   "source": [
    "bkg1frac = ROOT.RooRealVar(\"bkg1frac\", \"fraction of component 1 in background\", 0.2, 0.0, 1.0)\n",
    "bkg = ROOT.RooAddPdf(\"bkg\", \"Signal\", [bkg1, bkg2], [bkg1frac])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76505b7c",
   "metadata": {},
   "source": [
    "Sum the composite signal and background"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "300fd2b5",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:05.227289Z",
     "iopub.status.busy": "2026-05-19T20:30:05.227165Z",
     "iopub.status.idle": "2026-05-19T20:30:05.330921Z",
     "shell.execute_reply": "2026-05-19T20:30:05.330368Z"
    }
   },
   "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": "f7b2414e",
   "metadata": {},
   "source": [
    "Create dummy dataset that has more observables than the above pdf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "4feef7c9",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:05.332822Z",
     "iopub.status.busy": "2026-05-19T20:30:05.332697Z",
     "iopub.status.idle": "2026-05-19T20:30:05.520028Z",
     "shell.execute_reply": "2026-05-19T20:30:05.518974Z"
    }
   },
   "outputs": [],
   "source": [
    "y = ROOT.RooRealVar(\"y\", \"y\", -10, 10)\n",
    "data = ROOT.RooDataSet(\"data\", \"data\", {x, y})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed8022fa",
   "metadata": {},
   "source": [
    "Basic information requests\n",
    "---------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1074856",
   "metadata": {},
   "source": [
    "Get list of observables\n",
    "---------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a1f4376",
   "metadata": {},
   "source": [
    "Get list of observables of pdf in context of a dataset\n",
    "\n",
    "Observables are define each context as the variables\n",
    "shared between a model and a dataset. In self case\n",
    "that is the variable 'x'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "0db6ce16",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:05.521662Z",
     "iopub.status.busy": "2026-05-19T20:30:05.521520Z",
     "iopub.status.idle": "2026-05-19T20:30:05.632896Z",
     "shell.execute_reply": "2026-05-19T20:30:05.632358Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  1) 0x55aaa592f5d0 RooRealVar:: x = 5  L(0 - 10)  \"x\"\n"
     ]
    }
   ],
   "source": [
    "model_obs = model.getObservables(data)\n",
    "ROOT.SetOwnership(model_obs, True)\n",
    "model_obs.Print(\"v\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d181e1f",
   "metadata": {},
   "source": [
    "Get list of parameters\n",
    "-------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae3f82ea",
   "metadata": {},
   "source": [
    "Get list of parameters, list of observables"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "4f4fec35",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:05.640521Z",
     "iopub.status.busy": "2026-05-19T20:30:05.640391Z",
     "iopub.status.idle": "2026-05-19T20:30:05.755876Z",
     "shell.execute_reply": "2026-05-19T20:30:05.755304Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  1) 0x55aaa5a9ce30 RooRealVar::       a0 = 0.5  L(0 - 1)  \"a0\"\n",
      "  2) 0x55aaa5b69050 RooRealVar::       a1 = 0.2  L(0 - 1)  \"a1\"\n",
      "  3) 0x55aaa5b06c20 RooRealVar::    alpha = -1 C  L(-INF - +INF)  \"alpha\"\n",
      "  4) 0x55aaa5eea690 RooRealVar:: bkg1frac = 0.2  L(0 - 1)  \"fraction of component 1 in background\"\n",
      "  5) 0x55aaa5fa5270 RooRealVar::  bkgfrac = 0.5  L(0 - 1)  \"fraction of background\"\n",
      "  6) 0x55aaa5a72770 RooRealVar::     mean = 5 C  L(-INF - +INF)  \"mean of gaussians\"\n",
      "  7) 0x55aaa5a14060 RooRealVar::    sigma = 0.5 C  L(-INF - +INF)  \"width of gaussians\"\n"
     ]
    }
   ],
   "source": [
    "model_params = model.getParameters({x})\n",
    "ROOT.SetOwnership(model_params, True)\n",
    "model_params.Print(\"v\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15836886",
   "metadata": {},
   "source": [
    "Get list of parameters, a dataset\n",
    "(Gives identical results to operation above)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "18fb8c52",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:05.757491Z",
     "iopub.status.busy": "2026-05-19T20:30:05.757366Z",
     "iopub.status.idle": "2026-05-19T20:30:05.868183Z",
     "shell.execute_reply": "2026-05-19T20:30:05.867338Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RooArgSet::parameters = (a0,a1,alpha,bkg1frac,bkgfrac,mean,sigma)\n"
     ]
    }
   ],
   "source": [
    "model_params2 = model.getParameters(data)\n",
    "ROOT.SetOwnership(model_params2, True)\n",
    "model_params2.Print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cba73c94",
   "metadata": {},
   "source": [
    "Get list of components\n",
    "-------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "49116035",
   "metadata": {},
   "source": [
    "Get list of component objects, top-level node"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "3249d343",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:05.869757Z",
     "iopub.status.busy": "2026-05-19T20:30:05.869617Z",
     "iopub.status.idle": "2026-05-19T20:30:05.979232Z",
     "shell.execute_reply": "2026-05-19T20:30:05.978021Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  1) 0x55aaa604e470 RooAddPdf:: model[ bkgfrac * bkg + [%] * sig ] = 0.582695/1  \"g1+g2+a\"\n",
      "  2) 0x55aaa5ff3db0 RooAddPdf::   bkg[ bkg1frac * bkg1 + [%] * bkg2 ] = 0.16539/1  \"Signal\"\n",
      "  3) 0x55aaa4307600 RooChebychev::  bkg1[ x=x coefList=(a0,a1) ] = 0.8  \"Background 1\"\n",
      "  4) 0x55aaa5fb6030 RooExponential::  bkg2[ x=x c=alpha ] = 0.00673795  \"Background 2\"\n",
      "  5) 0x55aaa5a9a210 RooGaussian::   sig[ x=x mean=mean sigma=sigma ] = 1  \"Signal component 1\"\n"
     ]
    }
   ],
   "source": [
    "model_comps = model.getComponents()\n",
    "ROOT.SetOwnership(model_comps, True)\n",
    "model_comps.Print(\"v\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7c02af8",
   "metadata": {},
   "source": [
    "Modifications to structure of composites\n",
    "-------------------------------------------"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f932559c",
   "metadata": {},
   "source": [
    "Create a second Gaussian"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "afe3472c",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:05.980792Z",
     "iopub.status.busy": "2026-05-19T20:30:05.980667Z",
     "iopub.status.idle": "2026-05-19T20:30:06.085671Z",
     "shell.execute_reply": "2026-05-19T20:30:06.084863Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#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": [
    "sigma2 = ROOT.RooRealVar(\"sigma2\", \"width of gaussians\", 1)\n",
    "sig2 = ROOT.RooGaussian(\"sig2\", \"Signal component 1\", x, mean, sigma2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6549b5f0",
   "metadata": {},
   "source": [
    "Create a sum of the original Gaussian plus the second Gaussian"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "586f55b0",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:06.087176Z",
     "iopub.status.busy": "2026-05-19T20:30:06.087048Z",
     "iopub.status.idle": "2026-05-19T20:30:06.190610Z",
     "shell.execute_reply": "2026-05-19T20:30:06.190068Z"
    }
   },
   "outputs": [],
   "source": [
    "sig1frac = ROOT.RooRealVar(\"sig1frac\", \"fraction of component 1 in signal\", 0.8, 0.0, 1.0)\n",
    "sigsum = ROOT.RooAddPdf(\"sigsum\", \"sig+sig2\", [sig, sig2], [sig1frac])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8da73125",
   "metadata": {},
   "source": [
    "Construct a customizer utility to customize model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4c430d18",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:06.192546Z",
     "iopub.status.busy": "2026-05-19T20:30:06.192418Z",
     "iopub.status.idle": "2026-05-19T20:30:06.303313Z",
     "shell.execute_reply": "2026-05-19T20:30:06.302797Z"
    }
   },
   "outputs": [],
   "source": [
    "cust = ROOT.RooCustomizer(model, \"cust\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8bdd9792",
   "metadata": {},
   "source": [
    "Instruct the customizer to replace node 'sig' with node 'sigsum'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "7ff9fd1c",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:06.310433Z",
     "iopub.status.busy": "2026-05-19T20:30:06.310304Z",
     "iopub.status.idle": "2026-05-19T20:30:06.417908Z",
     "shell.execute_reply": "2026-05-19T20:30:06.417336Z"
    }
   },
   "outputs": [],
   "source": [
    "cust.replaceArg(sig, sigsum)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bcc9c025",
   "metadata": {},
   "source": [
    "Build a clone of the input pdf according to the above customization\n",
    "instructions. Each node that requires modified is clone so that the\n",
    "original pdf remained untouched. The name of each cloned node is that\n",
    "of the original node suffixed by the name of the customizer object\n",
    "\n",
    "The returned head node own all nodes that were cloned as part of\n",
    "the build process so when cust_clone is deleted so will all other\n",
    "nodes that were created in the process."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "35838473",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:06.419830Z",
     "iopub.status.busy": "2026-05-19T20:30:06.419703Z",
     "iopub.status.idle": "2026-05-19T20:30:06.529667Z",
     "shell.execute_reply": "2026-05-19T20:30:06.528892Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#1] INFO:ObjectHandling -- RooCustomizer::build(model): tree node sig will be replaced by sigsum\n",
      "[#1] INFO:ObjectHandling -- RooCustomizer::build(model) Branch node RooAddPdf::model cloned: depends on a replaced parameter\n",
      "[#1] INFO:ObjectHandling -- RooCustomizer::build(model) Branch node sig is already replaced\n"
     ]
    }
   ],
   "source": [
    "cust_clone = cust.build(True)\n",
    "ROOT.SetOwnership(cust_clone, True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9925ddd2",
   "metadata": {},
   "source": [
    "Print structure of clone of model with sig.sigsum replacement."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "5961884a",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:06.531121Z",
     "iopub.status.busy": "2026-05-19T20:30:06.530998Z",
     "iopub.status.idle": "2026-05-19T20:30:06.641254Z",
     "shell.execute_reply": "2026-05-19T20:30:06.640481Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0x55aaa642ca70 RooAddPdf::model_cust = 0.582695/1 [Auto,Clean] \n",
      "  0x55aaa5ff3db0/V- RooAddPdf::bkg = 0.16539/1 [Auto,Clean] \n",
      "    0x55aaa4307600/V- RooChebychev::bkg1 = 0.8 [Auto,Dirty] \n",
      "      0x55aaa592f5d0/V- RooRealVar::x = 5\n",
      "      0x55aaa5a9ce30/V- RooRealVar::a0 = 0.5\n",
      "      0x55aaa5b69050/V- RooRealVar::a1 = 0.2\n",
      "    0x55aaa5eea690/V- RooRealVar::bkg1frac = 0.2\n",
      "    0x55aaa5fb6030/V- RooExponential::bkg2 = 0.00673795 [Auto,Dirty] \n",
      "      0x55aaa592f5d0/V- RooRealVar::x = 5\n",
      "      0x55aaa5b06c20/V- RooRealVar::alpha = -1\n",
      "  0x55aaa5fa5270/V- RooRealVar::bkgfrac = 0.5\n",
      "  0x55aaa445cc40/V- RooAddPdf::sigsum = 1/1 [Auto,Clean] \n",
      "    0x55aaa5a9a210/V- RooGaussian::sig = 1 [Auto,Dirty] \n",
      "      0x55aaa592f5d0/V- RooRealVar::x = 5\n",
      "      0x55aaa5a72770/V- RooRealVar::mean = 5\n",
      "      0x55aaa5a14060/V- RooRealVar::sigma = 0.5\n",
      "    0x55aaa6436d90/V- RooRealVar::sig1frac = 0.8\n",
      "    0x55aaa626de50/V- RooGaussian::sig2 = 1 [Auto,Dirty] \n",
      "      0x55aaa592f5d0/V- RooRealVar::x = 5\n",
      "      0x55aaa5a72770/V- RooRealVar::mean = 5\n",
      "      0x55aaa6436750/V- RooRealVar::sigma2 = 1\n"
     ]
    }
   ],
   "source": [
    "cust_clone.Print(\"t\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ecb4e04",
   "metadata": {},
   "source": [
    "Draw all canvases "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "e8fc7e47",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:30:06.642750Z",
     "iopub.status.busy": "2026-05-19T20:30:06.642620Z",
     "iopub.status.idle": "2026-05-19T20:30:06.750131Z",
     "shell.execute_reply": "2026-05-19T20:30:06.749610Z"
    }
   },
   "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
}
