{ "cells": [ { "cell_type": "markdown", "id": "df9c6f2b", "metadata": {}, "source": [ "# rf514_RooCustomizer\n", "Using the RooCustomizer to create multiple PDFs that share a lot of properties, but have unique parameters for each category.\n", "As an extra complication, some of the new parameters need to be functions\n", "of a mass parameter.\n", "\n", "\n", "\n", "\n", "**Author:** Stephan Hageboeck, CERN \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:32 PM." ] }, { "cell_type": "markdown", "id": "6a7b01df", "metadata": {}, "source": [ "Define a proto model that will be used as the template for each category\n", "---------------------------------------------------------------------------" ] }, { "cell_type": "code", "execution_count": 1, "id": "afa692b3", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:32:47.916808Z", "iopub.status.busy": "2026-05-19T20:32:47.916694Z", "iopub.status.idle": "2026-05-19T20:32:48.483999Z", "shell.execute_reply": "2026-05-19T20:32:48.483303Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[#0] WARNING:InputArguments -- The parameter 'sigmaG' with range [-inf, inf] of the RooGaussian 'gauss' exceeds the safe range of (0, inf). Advise to limit its range.\n", "The proto model before customisation:\n", "0x7f5d86d75218 RooAddPdf::model = 750.5/1 [Auto,Clean] \n", " 0x7f5d86d73bc0/V- RooGaussian::gauss = 0 [Auto,Dirty] \n", " 0x7f5d86d73008/V- RooRealVar::Energy = 1500\n", " 0x7f5d86d733f0/V- RooRealVar::meanG = 100\n", " 0x7f5d86d737d8/V- RooRealVar::sigmaG = 3\n", " 0x7f5d86d74a48/V- RooRealVar::yieldSig = 1\n", " 0x7f5d86d74500/V- RooPolynomial::linear = 1501 [Auto,Dirty] \n", " 0x7f5d86d73008/V- RooRealVar::Energy = 1500\n", " 0x7f5d86d74118/V- RooRealVar::pol1 = 1\n", " 0x7f5d86d74e30/V- RooRealVar::yieldBkg = 1\n" ] } ], "source": [ "RooRealVar E(\"Energy\",\"Energy\",0,3000);\n", "\n", "RooRealVar meanG(\"meanG\",\"meanG\", 100., 0., 3000.);\n", "RooRealVar sigmaG(\"sigmaG\",\"sigmaG\", 3.);\n", "RooGaussian gauss(\"gauss\", \"gauss\", E, meanG, sigmaG);\n", "\n", "RooRealVar pol1(\"pol1\", \"Constant of the polynomial\", 1, -10, 10);\n", "RooPolynomial linear(\"linear\", \"linear\", E, pol1);\n", "\n", "RooRealVar yieldSig(\"yieldSig\", \"yieldSig\", 1, 0, 1.E4);\n", "RooRealVar yieldBkg(\"yieldBkg\", \"yieldBkg\", 1, 0, 1.E4);\n", "\n", "RooAddPdf model(\"model\", \"S + B model\",\n", " RooArgList(gauss,linear),\n", " RooArgList(yieldSig, yieldBkg));\n", "\n", "std::cout << \"The proto model before customisation:\" << std::endl;\n", "model.Print(\"T\"); // \"T\" prints the model as a tree" ] }, { "cell_type": "markdown", "id": "c563ce92", "metadata": {}, "source": [ "Build the categories" ] }, { "cell_type": "code", "execution_count": 2, "id": "feebd945", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:32:48.485446Z", "iopub.status.busy": "2026-05-19T20:32:48.485327Z", "iopub.status.idle": "2026-05-19T20:32:48.714855Z", "shell.execute_reply": "2026-05-19T20:32:48.697374Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "input_line_53:2:2: warning: 'sample' shadows a declaration with the same name in the 'std' namespace; use '::sample' to reference this declaration\n", " RooCategory sample(\"sample\",\"sample\");\n", " ^\n" ] } ], "source": [ "RooCategory sample(\"sample\",\"sample\");\n", "sample[\"Sample1\"] = 1;\n", "sample[\"Sample2\"] = 2;\n", "sample[\"Sample3\"] = 3;" ] }, { "cell_type": "markdown", "id": "69baf675", "metadata": {}, "source": [ "Start to customise the proto model that was defined above.\n", "---------------------------------------------------------------------------" ] }, { "cell_type": "markdown", "id": "67b0afa5", "metadata": {}, "source": [ "We need two sets for bookkeeping of PDF nodes:" ] }, { "cell_type": "code", "execution_count": 3, "id": "0e030827", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:32:48.716620Z", "iopub.status.busy": "2026-05-19T20:32:48.716480Z", "iopub.status.idle": "2026-05-19T20:32:48.922356Z", "shell.execute_reply": "2026-05-19T20:32:48.921751Z" } }, "outputs": [], "source": [ "RooArgSet newLeaves; // This set collects leaves that are created in the process.\n", "RooArgSet allCustomiserNodes; // This set lists leaves that have been used in a replacement operation." ] }, { "cell_type": "markdown", "id": "0480a786", "metadata": {}, "source": [ "1. Each sample should have its own mean for the gaussian\n", "The customiser will make copies of `meanG` for each category.\n", "These will all appear in the set `newLeaves`, which will own the new nodes." ] }, { "cell_type": "code", "execution_count": 4, "id": "d4fec911", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:32:48.923989Z", "iopub.status.busy": "2026-05-19T20:32:48.923870Z", "iopub.status.idle": "2026-05-19T20:32:49.133197Z", "shell.execute_reply": "2026-05-19T20:32:49.132623Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "input_line_55:2:28: error: reference to 'sample' is ambiguous\n", " RooCustomizer cust(model, sample, newLeaves, &allCustomiserNodes);\n", " ^\n", "input_line_53:2:14: note: candidate found by name lookup is 'sample'\n", " RooCategory sample(\"sample\",\"sample\");\n", " ^\n", "/usr/lib/gcc/x86_64-redhat-linux/14/../../../../include/c++/14/bits/stl_algo.h:5826:5: note: candidate found by name lookup is 'std::sample'\n", " sample(_PopulationIterator __first, _PopulationIterator __last,\n", " ^\n", "input_line_55:3:22: error: reference to 'sample' is ambiguous\n", "cust.splitArg(meanG, sample);\n", " ^\n", "input_line_53:2:14: note: candidate found by name lookup is 'sample'\n", " RooCategory sample(\"sample\",\"sample\");\n", " ^\n", "/usr/lib/gcc/x86_64-redhat-linux/14/../../../../include/c++/14/bits/stl_algo.h:5826:5: note: candidate found by name lookup is 'std::sample'\n", " sample(_PopulationIterator __first, _PopulationIterator __last,\n", " ^\n" ] } ], "source": [ "RooCustomizer cust(model, sample, newLeaves, &allCustomiserNodes);\n", "cust.splitArg(meanG, sample);" ] }, { "cell_type": "markdown", "id": "7408cad4", "metadata": {}, "source": [ "2. Each sample should have its own signal yield, but there is an extra complication:\n", "We need the yields 1 and 2 to be a function of the variable \"mass\".\n", "For this, we pre-define nodes with exactly the names that the customiser would have created automatically,\n", "that is, \"_\", and we register them in the set of customiser nodes.\n", "The customiser will pick them up instead of creating new ones.\n", "If we don't provide one (e.g. for \"yieldSig_Sample3\"), it will be created automatically by cloning `yieldSig`." ] }, { "cell_type": "code", "execution_count": 5, "id": "8ceb1cf2", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:32:49.134599Z", "iopub.status.busy": "2026-05-19T20:32:49.134483Z", "iopub.status.idle": "2026-05-19T20:32:49.343130Z", "shell.execute_reply": "2026-05-19T20:32:49.342497Z" } }, "outputs": [], "source": [ "RooRealVar mass(\"M\", \"M\", 1, 0, 12000);\n", "RooFormulaVar yield1(\"yieldSig_Sample1\", \"Signal yield in the first sample\", \"M/3.360779\", mass);\n", "RooFormulaVar yield2(\"yieldSig_Sample2\", \"Signal yield in the second sample\", \"M/2\", mass);\n", "allCustomiserNodes.add(yield1);\n", "allCustomiserNodes.add(yield2);" ] }, { "cell_type": "markdown", "id": "48bb7e63", "metadata": {}, "source": [ "Instruct the customiser to replace all yieldSig nodes for each sample:" ] }, { "cell_type": "code", "execution_count": 6, "id": "7cc75a96", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:32:49.344955Z", "iopub.status.busy": "2026-05-19T20:32:49.344837Z", "iopub.status.idle": "2026-05-19T20:32:49.553700Z", "shell.execute_reply": "2026-05-19T20:32:49.553137Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "input_line_69:2:26: error: reference to 'sample' is ambiguous\n", " cust.splitArg(yieldSig, sample);\n", " ^\n", "input_line_53:2:14: note: candidate found by name lookup is 'sample'\n", " RooCategory sample(\"sample\",\"sample\");\n", " ^\n", "/usr/lib/gcc/x86_64-redhat-linux/14/../../../../include/c++/14/bits/stl_algo.h:5826:5: note: candidate found by name lookup is 'std::sample'\n", " sample(_PopulationIterator __first, _PopulationIterator __last,\n", " ^\n" ] } ], "source": [ "cust.splitArg(yieldSig, sample);" ] }, { "cell_type": "markdown", "id": "053bb15a", "metadata": {}, "source": [ "Now we can start building the PDFs for all categories:" ] }, { "cell_type": "code", "execution_count": 7, "id": "e35eb14e", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:32:49.555257Z", "iopub.status.busy": "2026-05-19T20:32:49.555147Z", "iopub.status.idle": "2026-05-19T20:32:49.760831Z", "shell.execute_reply": "2026-05-19T20:32:49.760277Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "input_line_70:2:14: error: cannot deduce 'auto' from unknown expression\n", " auto pdf1 = cust.build(\"Sample1\");\n", " ^\n" ] } ], "source": [ "auto pdf1 = cust.build(\"Sample1\");\n", "auto pdf2 = cust.build(\"Sample2\");\n", "auto pdf3 = cust.build(\"Sample3\");" ] }, { "cell_type": "markdown", "id": "58fb3d42", "metadata": {}, "source": [ "And we inspect the two PDFs" ] }, { "cell_type": "code", "execution_count": 8, "id": "a99ae4d1", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:32:49.762243Z", "iopub.status.busy": "2026-05-19T20:32:49.762129Z", "iopub.status.idle": "2026-05-19T20:32:49.967975Z", "shell.execute_reply": "2026-05-19T20:32:49.967433Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "PDF 1 with a yield depending on M:\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "input_line_72:2:3: error: use of undeclared identifier 'pdf1'\n", " (pdf1->Print(\"T\"))\n", " ^\n", "Error in : Error evaluating expression (pdf1->Print(\"T\"))\n", "Execution of your code was aborted.\n" ] } ], "source": [ "std::cout << \"\\nPDF 1 with a yield depending on M:\" << std::endl;\n", "pdf1->Print(\"T\");\n", "std::cout << \"\\nPDF 2 with a yield depending on M:\" << std::endl;\n", "pdf2->Print(\"T\");\n", "std::cout << \"\\nPDF 3 with a free yield:\" << std::endl;\n", "pdf3->Print(\"T\");\n", "\n", "std::cout << \"\\nThe following leaves have been created automatically while customising:\" << std::endl;\n", "newLeaves.Print(\"V\");" ] }, { "cell_type": "markdown", "id": "0ec1f19d", "metadata": {}, "source": [ "If we needed to set reasonable values for the means of the gaussians, this could be done as follows:" ] }, { "cell_type": "code", "execution_count": 9, "id": "ac9587ec", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:32:49.969466Z", "iopub.status.busy": "2026-05-19T20:32:49.969354Z", "iopub.status.idle": "2026-05-19T20:32:50.174977Z", "shell.execute_reply": "2026-05-19T20:32:50.174493Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[#0] ERROR:InputArguments -- RooArgSet::operator[]() ERROR: no element named meanG_Sample1 in set\n" ] } ], "source": [ "auto& meanG1 = static_cast(allCustomiserNodes[\"meanG_Sample1\"]);\n", "meanG1.setVal(200);\n", "auto& meanG2 = static_cast(allCustomiserNodes[\"meanG_Sample2\"]);\n", "meanG2.setVal(300);\n", "\n", "std::cout << \"\\nThe following leaves have been used while customising\"\n", " << \"\\n\\t(partial overlap with the set of automatically created leaves.\"\n", " << \"\\n\\ta new customiser for a different PDF could reuse them if necessary.):\" << std::endl;\n", "allCustomiserNodes.Print(\"V\");" ] } ], "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 }