Using the RooCustomizer to create multiple PDFs that share a lot of properties, but have unique parameters for each category. As an extra complication, some of the new parameters need to be functions of a mass parameter.
Author: Stephan Hageboeck, CERN
This notebook tutorial was automatically generated with ROOTBOOK-izer from the macro found in the ROOT repository on Tuesday, March 19, 2024 at 07:16 PM.
RooRealVar E("Energy","Energy",0,3000);
RooRealVar meanG("meanG","meanG", 100., 0., 3000.);
RooRealVar sigmaG("sigmaG","sigmaG", 3.);
RooGaussian gauss("gauss", "gauss", E, meanG, sigmaG);
RooRealVar pol1("pol1", "Constant of the polynomial", 1, -10, 10);
RooPolynomial linear("linear", "linear", E, pol1);
RooRealVar yieldSig("yieldSig", "yieldSig", 1, 0, 1.E4);
RooRealVar yieldBkg("yieldBkg", "yieldBkg", 1, 0, 1.E4);
RooAddPdf model("model", "S + B model",
RooArgList(gauss,linear),
RooArgList(yieldSig, yieldBkg));
std::cout << "The proto model before customisation:" << std::endl;
model.Print("T"); // "T" prints the model as a tree
[#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. The proto model before customisation: 0x7f6830096210 RooAddPdf::model = 750.5/1 [Auto,Clean] 0x7f6830094bb8/V- RooGaussian::gauss = 0 [Auto,Dirty] 0x7f6830094000/V- RooRealVar::Energy = 1500 0x7f68300943e8/V- RooRealVar::meanG = 100 0x7f68300947d0/V- RooRealVar::sigmaG = 3 0x7f6830095a40/V- RooRealVar::yieldSig = 1 0x7f68300954f8/V- RooPolynomial::linear = 1501 [Auto,Dirty] 0x7f6830094000/V- RooRealVar::Energy = 1500 0x7f6830095110/V- RooRealVar::pol1 = 1 0x7f6830095e28/V- RooRealVar::yieldBkg = 1
Build the categories
RooCategory sample("sample","sample");
sample["Sample1"] = 1;
sample["Sample2"] = 2;
sample["Sample3"] = 3;
input_line_52:2:2: warning: 'sample' shadows a declaration with the same name in the 'std' namespace; use '::sample' to reference this declaration RooCategory sample("sample","sample"); ^
We need two sets for bookkeeping of PDF nodes:
RooArgSet newLeafs; // This set collects leafs that are created in the process.
RooArgSet allCustomiserNodes; // This set lists leafs that have been used in a replacement operation.
The customiser will make copies of meanG
for each category.
These will all appear in the set newLeafs
, which will own the new nodes.
RooCustomizer cust(model, sample, newLeafs, &allCustomiserNodes);
cust.splitArg(meanG, sample);
input_line_54:2:28: error: reference to 'sample' is ambiguous RooCustomizer cust(model, sample, newLeafs, &allCustomiserNodes); ^ input_line_52:2:14: note: candidate found by name lookup is 'sample' RooCategory sample("sample","sample"); ^ /usr/include/c++/9/bits/stl_algo.h:5855:5: note: candidate found by name lookup is 'std::sample' sample(_PopulationIterator __first, _PopulationIterator __last, ^ input_line_54:3:22: error: reference to 'sample' is ambiguous cust.splitArg(meanG, sample); ^ input_line_52:2:14: note: candidate found by name lookup is 'sample' RooCategory sample("sample","sample"); ^ /usr/include/c++/9/bits/stl_algo.h:5855:5: note: candidate found by name lookup is 'std::sample' sample(_PopulationIterator __first, _PopulationIterator __last, ^
We need the yields 1 and 2 to be a function of the variable "mass".
For this, we pre-define nodes with exactly the names that the customiser would have created automatically,
that is, "yieldSig
.
RooRealVar mass("M", "M", 1, 0, 12000);
RooFormulaVar yield1("yieldSig_Sample1", "Signal yield in the first sample", "M/3.360779", mass);
RooFormulaVar yield2("yieldSig_Sample2", "Signal yield in the second sample", "M/2", mass);
allCustomiserNodes.add(yield1);
allCustomiserNodes.add(yield2);
Instruct the customiser to replace all yieldSig nodes for each sample:
cust.splitArg(yieldSig, sample);
input_line_62:2:26: error: reference to 'sample' is ambiguous cust.splitArg(yieldSig, sample); ^ input_line_52:2:14: note: candidate found by name lookup is 'sample' RooCategory sample("sample","sample"); ^ /usr/include/c++/9/bits/stl_algo.h:5855:5: note: candidate found by name lookup is 'std::sample' sample(_PopulationIterator __first, _PopulationIterator __last, ^
Now we can start building the PDFs for all categories:
auto pdf1 = cust.build("Sample1");
auto pdf2 = cust.build("Sample2");
auto pdf3 = cust.build("Sample3");
input_line_63:2:2: error: Syntax error auto pdf1 = cust.build("Sample1"); ^ FunctionDecl 0x7f6816795830 <input_line_63:1:1, line:6:1> line:1:6 __cling_Un1Qu325 'void (void *)' |-ParmVarDecl 0x7f6816795778 <col:23, col:29> col:29 vpClingValue 'void *' |-CompoundStmt 0x7f6816796090 <col:43, line:6:1> | |-DeclStmt 0x7f6816795b90 <line:2:2, col:35> | | `-VarDecl 0x7f6816795948 <col:2, col:34> col:7 pdf1 'auto' cinit | | `-CallExpr 0x7f6816795b68 <col:14, col:34> '<dependent type>' | | |-CXXDependentScopeMemberExpr 0x7f6816795b00 <col:14, col:19> '<dependent type>' lvalue .build | | | `-DeclRefExpr 0x7f6816795ac0 <col:14> '<dependent type>' lvalue Var 0x7f68167959b8 'cust' '<dependent type>' | | `-StringLiteral 0x7f6816795b48 <col:25> 'const char[8]' lvalue "Sample1" | |-DeclStmt 0x7f6816795e00 <line:3:1, col:34> | | `-VarDecl 0x7f6816795bf0 <col:1, col:33> col:6 pdf2 'auto' cinit | | `-CallExpr 0x7f6816795dd8 <col:13, col:33> '<dependent type>' | | |-CXXDependentScopeMemberExpr 0x7f6816795d70 <col:13, col:18> '<dependent type>' lvalue .build | | | `-DeclRefExpr 0x7f6816795d30 <col:13> '<dependent type>' lvalue Var 0x7f6816795c60 'cust' '<dependent type>' | | `-StringLiteral 0x7f6816795db8 <col:24> 'const char[8]' lvalue "Sample2" | |-DeclStmt 0x7f6816796070 <line:4:1, col:34> | | `-VarDecl 0x7f6816795e60 <col:1, col:33> col:6 pdf3 'auto' cinit | | `-CallExpr 0x7f6816796048 <col:13, col:33> '<dependent type>' | | |-CXXDependentScopeMemberExpr 0x7f6816795fe0 <col:13, col:18> '<dependent type>' lvalue .build | | | `-DeclRefExpr 0x7f6816795fa0 <col:13> '<dependent type>' lvalue Var 0x7f6816795ed0 'cust' '<dependent type>' | | `-StringLiteral 0x7f6816796028 <col:24> 'const char[8]' lvalue "Sample3" | `-NullStmt 0x7f6816796088 <line:5:1> |-AnnotateAttr 0x7f6816795a20 <<invalid sloc>> Implicit R"ATTRDUMP(__ResolveAtRuntime)ATTRDUMP" |-AnnotateAttr 0x7f6816795cc8 <<invalid sloc>> Implicit R"ATTRDUMP(__ResolveAtRuntime)ATTRDUMP" `-AnnotateAttr 0x7f6816795f38 <<invalid sloc>> Implicit R"ATTRDUMP(__ResolveAtRuntime)ATTRDUMP" <<<NULL>>>
And we inspect the two PDFs
std::cout << "\nPDF 1 with a yield depending on M:" << std::endl;
pdf1->Print("T");
std::cout << "\nPDF 2 with a yield depending on M:" << std::endl;
pdf2->Print("T");
std::cout << "\nPDF 3 with a free yield:" << std::endl;
pdf3->Print("T");
std::cout << "\nThe following leafs have been created automatically while customising:" << std::endl;
newLeafs.Print("V");
PDF 1 with a yield depending on M:
input_line_65:2:3: error: use of undeclared identifier 'pdf1' (pdf1->Print("T")) ^ Error in <HandleInterpreterException>: Error evaluating expression (pdf1->Print("T")) Execution of your code was aborted.
If we needed to set reasonable values for the means of the gaussians, this could be done as follows:
auto& meanG1 = static_cast<RooRealVar&>(allCustomiserNodes["meanG_Sample1"]);
meanG1.setVal(200);
auto& meanG2 = static_cast<RooRealVar&>(allCustomiserNodes["meanG_Sample2"]);
meanG2.setVal(300);
std::cout << "\nThe following leafs have been used while customising"
<< "\n\t(partial overlap with the set of automatically created leaves."
<< "\n\ta new customiser for a different PDF could reuse them if necessary.):" << std::endl;
allCustomiserNodes.Print("V");
[#0] ERROR:InputArguments -- RooArgSet::operator[]() ERROR: no element named meanG_Sample1 in set