Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooCustomizer.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/**
18 * \class RooCustomizer
19 *
20 * RooCustomizer is a factory class to produce clones
21 * of a prototype composite PDF object with the same structure but
22 * different leaf servers (parameters or dependents).
23 *
24 * RooCustomizer supports two kinds of modifications:
25 *
26 * - replaceArg(leaf_arg, repl_arg):
27 * Replaces each occurrence of leaf_arg with repl_arg in the composite pdf.
28 *
29 * - splitArg(split_arg):
30 * Build multiple clones of the same prototype. Each
31 * occurrence of split_arg is replaced with a clone of split_arg
32 * named split_arg_[MCstate], where [MCstate] is the name of the
33 * 'master category state' that indexes the clones to be built.
34 *
35 *
36 * ### Example: Change the decay constant of an exponential for each run
37 *
38 * Splitting is particularly useful when building simultaneous fits to
39 * subsets of the data sample with different background properties.
40 * In such a case, the user builds a single prototype PDF representing
41 * the structure of the signal and background and splits the dataset
42 * into categories with different background properties. Using
43 * RooCustomizer a PDF for each subfit can be constructed from the
44 * prototype that has same structure and signal parameters, but
45 * different instances of the background parameters: e.g.
46 * ```
47 * ...
48 * RooExponential bg("bg","background",x,alpha) ;
49 * RooGaussian sig("sig","signal",x,mean,sigma) ;
50 * RooAddPdf pdf("pdf","pdf",sig,bg,sigfrac) ;
51 *
52 * RooDataSet data("data","dataset",RooArgSet(x,runblock),...)
53 *
54 * RooCategory runblock("runblock","run block") ;
55 * runblock.defineType("run1") ;
56 * runblock.defineType("run2") ;
57 *
58 * RooArgSet splitLeaves;
59 * RooCustomizer cust(pdf,runblock,splitLeaves);
60 * cust.splitArg(alpha,runblock);
61 *
62 * RooAbsPdf* pdf_run1 = cust.build("run1") ;
63 * RooAbsPdf* pdf_run2 = cust.build("run2") ;
64 *
65 * RooSimultaneous simpdf("simpdf","simpdf",RooArgSet(*pdf_run1,*pdf_run2))
66 * ```
67 * If the master category state is a super category, leaves may be split
68 * by any subset of that master category. E.g. if the master category
69 * is 'A x B', leaves may be split by A, B or AxB.
70 *
71 * In addition to replacing leaf nodes, RooCustomizer clones all branch
72 * nodes that depend directly or indirectly on modified leaf nodes, so
73 * that the input pdf is untouched by each build operation.
74 *
75 * The customizer owns all the branch nodes including the returned top
76 * level node, so the customizer should live as longs as the cloned
77 * composites are needed.
78 *
79 * Any leaf nodes that are created by the customizer will be put into
80 * the leaf list that is passed into the customizers constructor (splitLeaves in
81 * the above example. The list owner is responsible for deleting these leaf
82 * nodes after the customizer is deleted.
83 *
84 *
85 * ## Advanced techniques
86 *
87 * ### Reuse nodes to customise a different PDF
88 * By default, the customizer clones the prototype leaf node when splitting a leaf,
89 * but the user can feed pre-defined split leaves in leaf list. These leaves
90 * must have the name `<split_leaf>_<splitcat_label>` to be picked up. The list
91 * of pre-supplied leaves may be partial, any missing split leaves will be auto
92 * generated.
93 *
94 * Another common construction is to have two prototype PDFs, each to be customized
95 * by a separate customizer instance, that share parameters. To ensure that
96 * the customized clones also share their respective split leaves, i.e.
97 * ```
98 * PDF1(x,y, A) and PDF2(z, A) ---> PDF1_run1(x,y, A_run1) and PDF2_run1(x,y, A_run1)
99 * PDF1_run2(x,y, A_run2) and PDF2_run2(x,y, A_run2)
100 * ```
101 * feed the same split leaf list into both customizers. In that case, the second customizer
102 * will pick up the split leaves instantiated by the first customizer and the link between
103 * the two PDFs is retained.
104 *
105 * ### Customising with pre-defined leaves
106 * If leaf nodes are provided in the sets, the customiser will use them. This is a complete
107 * example that customises the `yield` parameter, and splits (automatically clones) the
108 * mean of the Gaussian. This is a short version of the tutorial rf514_RooCustomizer.C.
109 * ```
110 * RooRealVar E("Energy","Energy",0,3000);
111 *
112 * RooRealVar meanG("meanG","meanG", peak[1]);
113 * RooRealVar fwhm("fwhm", "fwhm", 5/(2*Sqrt(2*Log(2))));
114 * RooGaussian gauss("gauss", "gauss", E, meanG, fwhm);
115 *
116 * RooPolynomial linear("linear","linear",E,RooArgList());
117 *
118 * RooRealVar yieldSig("yieldSig", "yieldSig", 1, 0, 1.E4);
119 * RooRealVar yieldBkg("yieldBkg", "yieldBkg", 1, 0, 1.E4);
120 *
121 * RooAddPdf model("model","model",
122 * RooArgList(gauss,linear),
123 * RooArgList(yieldSig, yieldBkg));
124 *
125 * RooCategory sample("sample","sample");
126 * sample.defineType("BBG1m2T");
127 * sample.defineType("BBG2m2T");
128 *
129 *
130 * RooArgSet customisedLeaves;
131 * RooArgSet allLeaves;
132 *
133 * RooRealVar mass("M", "M", 1, 0, 12000);
134 * RooFormulaVar yield1("yieldSig_BBG1m2T","sigy1","M/3.360779",mass);
135 * RooFormulaVar yield2("yieldSig_BBG2m2T","sigy2","M/2",mass);
136 * allLeaves.add(yield1);
137 * allLeaves.add(yield2);
138 *
139 *
140 * RooCustomizer cust(model, sample, customisedLeaves, &allLeaves);
141 * cust.splitArg(yieldSig, sample);
142 * cust.splitArg(meanG, sample);
143 *
144 * auto pdf1 = cust.build("BBG1m2T");
145 * auto pdf2 = cust.build("BBG2m2T");
146 * ```
147*/
148
149
150#include "RooCustomizer.h"
151
152#include "RooFactoryWSTool.h"
153#include "RooAbsCategoryLValue.h"
154#include "RooAbsCategory.h"
155#include "RooAbsArg.h"
156#include "RooAbsPdf.h"
157#include "RooArgSet.h"
158#include "RooArgList.h"
159#include "RooMsgService.h"
160#include "RooHelpers.h"
161
162#include <iostream>
163#include "strtok.h"
164#include "strlcpy.h"
165
166#include "RooWorkspace.h"
167#include "RooGlobalFunc.h"
168#include "RooConstVar.h"
169#include "RooRealConstant.h"
170
171
172#ifndef _WIN32
173#include <strings.h>
174#endif
175
176
177using std::endl, std::ostream, std::string;
178
179
180namespace {
181
182/// Factory interface
183class CustIFace : public RooFactoryWSTool::IFace {
184public:
185 std::string create(RooFactoryWSTool& ft, const char* typeName, const char* instanceName, std::vector<std::string> args) override ;
186} ;
187
188
189static Int_t init();
190
191Int_t dummy = init() ;
192
193Int_t init()
194{
195 RooFactoryWSTool::IFace* iface = new CustIFace ;
197 (void) dummy;
198 return 0 ;
199}
200
201}
202
203////////////////////////////////////////////////////////////////////////////////
204/// Constructor with a prototype and masterCat index category.
205/// Customizers created by this constructor offer both the
206/// replaceArg() and splitArg() functionality.
207/// \param[in] pdf Proto PDF to be customised.
208/// \param[in] masterCat Category to be used for splitting.
209/// \param[in,out] splitLeaves All nodes created in
210/// the customisation process are added to this set.
211/// The user can provide nodes that are *taken*
212/// from the set if they have a name that matches `<parameterNameToBeReplaced>_<category>`.
213/// \note The set needs to own its contents if they are user-provided.
214/// Use *e.g.*
215/// ```
216/// RooArgSet customisedLeaves;
217/// auto yield1 = new RooFormulaVar("yieldSig_BBG1m2T","sigy1","M/3.360779",mass);
218/// customisedLeaves.addOwned(*yield1);
219/// ```
220/// \param[in,out] splitLeavesAll All leaves that are used when customising are collected here.
221/// If this set already contains leaves, they will be used for customising if the names match
222/// as above.
223///
224
225RooCustomizer::RooCustomizer(const RooAbsArg &pdf, const RooAbsCategoryLValue &masterCat, RooArgSet &splitLeaves,
226 RooArgSet *splitLeavesAll)
227 : _sterile(false),
228 _owning(true),
229 _masterPdf(const_cast<RooAbsArg *>(&pdf)),
230 _masterCat(const_cast<RooAbsCategoryLValue *>(&masterCat)),
231 _masterBranchList("masterBranchList"),
232 _masterLeafList("masterLeafList"),
233 _internalCloneBranchList("cloneBranchList"),
234 _cloneBranchList(&_internalCloneBranchList),
235 _cloneNodeListAll(splitLeavesAll),
236 _cloneNodeListOwned(&splitLeaves)
237{
238
239 initialize() ;
240}
241
242
243
244////////////////////////////////////////////////////////////////////////////////
245/// Sterile Constructor. Customizers created by this constructor
246/// offer only the replace() method. The supplied 'name' is used as
247/// suffix for any cloned branch nodes
248
250 : _sterile(true),
251 _owning(false),
252 _name(name),
253 _masterPdf(const_cast<RooAbsArg *>(&pdf)),
254 _masterBranchList("masterBranchList"),
255 _masterLeafList("masterLeafList"),
256 _internalCloneBranchList("cloneBranchList"),
257 _cloneBranchList(&_internalCloneBranchList)
258{
259
260 initialize() ;
261}
262
263
264
265
266////////////////////////////////////////////////////////////////////////////////
267/// Initialize the customizer
268
270{
273}
274
275////////////////////////////////////////////////////////////////////////////////
276/// Split all arguments in 'set' into individualized clones for each
277/// defined state of 'splitCat'. The 'splitCats' category must be
278/// subset of or equal to the master category supplied in the
279/// customizer constructor.
280///
281/// Splitting is only available on customizers created with a master index category
282
283void RooCustomizer::splitArgs(const RooArgSet& set, const RooAbsCategory& splitCat)
284{
285 if (_sterile) {
286 oocoutE(nullptr, InputArguments) << "RooCustomizer::splitArgs(" << _name
287 << ") ERROR cannot set spitting rules on this sterile customizer" << endl ;
288 return ;
289 }
290
291 for (auto arg : set) {
292 splitArg(*arg,splitCat) ;
293 }
294}
295
296
297
298////////////////////////////////////////////////////////////////////////////////
299/// Split all argument 'arg' into individualized clones for each
300/// defined state of 'splitCat'. The 'splitCats' category must be
301/// subset of or equal to the master category supplied in the
302/// customizer constructor.
303///
304/// Splitting is only available on customizers created with a master index category
305
306void RooCustomizer::splitArg(const RooAbsArg& arg, const RooAbsCategory& splitCat)
307{
308 if (_splitArgList.FindObject(arg.GetName())) {
309 oocoutE(nullptr, InputArguments) << "RooCustomizer(" << _masterPdf->GetName() << ") ERROR: multiple splitting rules defined for "
310 << arg.GetName() << " only using first rule" << endl ;
311 return ;
312 }
313
314 if (_sterile) {
315 oocoutE(nullptr, InputArguments) << "RooCustomizer::splitArg(" << _name
316 << ") ERROR cannot set spitting rules on this sterile customizer" << endl ;
317 return ;
318 }
319
320 _splitArgList.Add(const_cast<RooAbsArg *>(&arg));
321 _splitCatList.Add(const_cast<RooAbsCategory *>(&splitCat));
322}
323
324
325
326////////////////////////////////////////////////////////////////////////////////
327/// Replace any occurrence of arg 'orig' with arg 'subst'
328
329void RooCustomizer::replaceArg(const RooAbsArg& orig, const RooAbsArg& subst)
330{
331 if (_replaceArgList.FindObject(orig.GetName())) {
332 oocoutE(nullptr, InputArguments) << "RooCustomizer(" << _masterPdf->GetName() << ") ERROR: multiple replacement rules defined for "
333 << orig.GetName() << " only using first rule" << endl ;
334 return ;
335 }
336
337 _replaceArgList.Add(const_cast<RooAbsArg *>(&orig));
338 _replaceSubList.Add(const_cast<RooAbsArg *>(&subst));
339}
340
341
342
343////////////////////////////////////////////////////////////////////////////////
344/// Build a clone of the prototype executing all registered 'replace' rules.
345/// If verbose is set, a message is printed for each leaf or branch node
346/// modification. The returned head node owns all cloned branch nodes
347/// that were created in the cloning process.
348
350{
351 // Execute build
352 RooAbsArg* ret = doBuild(_name.Length()>0?_name.Data():nullptr,verbose) ;
353
354 // Make root object own all cloned nodes
355
356 // First make list of all objects that were created
357 RooArgSet allOwned ;
359 allOwned.add(*_cloneNodeListOwned) ;
360 }
361 allOwned.add(*_cloneBranchList) ;
362
363 // Remove head node from list
364 allOwned.remove(*ret) ;
365
366 // If list with owned objects is not empty, assign
367 // head node as owner
368 if (!allOwned.empty()) {
369 ret->addOwnedComponents(allOwned) ;
370 }
371
372 return ret ;
373}
374
375
376
377////////////////////////////////////////////////////////////////////////////////
378/// Build a clone of the prototype executing all registered 'replace'
379/// rules and 'split' rules for the masterCat state named
380/// 'masterCatState'. If verbose is set a message is printed for
381/// each leaf or branch node modification. The returned composite arg
382/// is owned by the customizer. This function cannot be called on
383/// customizer build with the sterile constructor.
384
385RooAbsArg* RooCustomizer::build(const char* masterCatState, bool verbose)
386{
387 if (_sterile) {
388 oocoutE(nullptr, InputArguments) << "RooCustomizer::build(" << _name
389 << ") ERROR cannot use leaf spitting build() on this sterile customizer" << endl ;
390 return nullptr ;
391 }
392
393 // Set masterCat to given state
394 if (_masterCat->setLabel(masterCatState)) {
395 oocoutE(nullptr, InputArguments) << "RooCustomizer::build(" << _masterPdf->GetName() << "): ERROR label '" << masterCatState
396 << "' not defined for master splitting category " << _masterCat->GetName() << endl ;
397 return nullptr ;
398 }
399
400 return doBuild(masterCatState,verbose) ;
401}
402
403
404
405////////////////////////////////////////////////////////////////////////////////
406/// Back-end implementation of the p.d.f building functionality
407
408RooAbsArg* RooCustomizer::doBuild(const char* masterCatState, bool verbose)
409{
410 // Find nodes that must be split according to provided description, Clone nodes, change their names
411 RooArgSet masterNodesToBeSplit("masterNodesToBeSplit") ;
412 RooArgSet masterNodesToBeReplaced("masterNodesToBeReplaced") ;
413 RooArgSet masterReplacementNodes("masterReplacementNodes") ;
414 RooArgSet clonedMasterNodes("clonedMasterNodes") ;
415
416
417 RooArgSet nodeList(_masterLeafList) ;
418 nodeList.add(_masterBranchList) ;
419
420 // cout << "loop over " << nodeList.size() << " nodes" << endl ;
421 for (auto node : nodeList) {
422 RooAbsArg* theSplitArg = !_sterile?static_cast<RooAbsArg*>(_splitArgList.FindObject(node->GetName())):nullptr ;
423 if (theSplitArg) {
424 RooAbsCategory* splitCat = static_cast<RooAbsCategory*>(_splitCatList.At(_splitArgList.IndexOf(theSplitArg))) ;
425 if (verbose) {
426 oocoutI(nullptr, ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
427 << "): tree node " << node->GetName() << " is split by category " << splitCat->GetName() << endl ;
428 }
429
430 TString newName(node->GetName()) ;
431 if (masterCatState) {
432 newName.Append("_") ;
433 newName.Append(splitCat->getCurrentLabel()) ;
434 }
435
436 // Check if this node instance already exists
437 RooAbsArg* specNode = _cloneNodeListAll ? _cloneNodeListAll->find(newName) : _cloneNodeListOwned->find(newName) ;
438 if (specNode) {
439
440 // Copy instance to one-time use list for this build
441 clonedMasterNodes.add(*specNode) ;
442 if (verbose) {
443 oocoutI(nullptr, ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
444 << ") Adding existing node specialization " << newName << " to clonedMasterNodes" << endl ;
445 }
446
447 // Affix attribute with old name to clone to support name changing server redirect
448 TString nameAttrib("ORIGNAME:") ;
449 nameAttrib.Append(node->GetName()) ;
450 specNode->setAttribute(nameAttrib) ;
451
452 if (!specNode->getStringAttribute("origName")) {
453 specNode->setStringAttribute("origName",node->GetName()) ;
454 }
455
456
457
458 } else {
459
460 if (node->isDerived()) {
461 oocoutW(nullptr, ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
462 << "): WARNING: branch node " << node->GetName() << " is split but has no pre-defined specializations" << endl ;
463 }
464
465 TString newTitle(node->GetTitle()) ;
466 newTitle.Append(" (") ;
467 newTitle.Append(splitCat->getCurrentLabel()) ;
468 newTitle.Append(")") ;
469
470 // Create a new clone
471 RooAbsArg* clone = static_cast<RooAbsArg*>(node->Clone(newName.Data())) ;
472 clone->removeStringAttribute("factory_tag") ;
473 clone->SetTitle(newTitle) ;
474
475 // Affix attribute with old name to clone to support name changing server redirect
476 TString nameAttrib("ORIGNAME:") ;
477 nameAttrib.Append(node->GetName()) ;
478 clone->setAttribute(nameAttrib) ;
479
480 if (!clone->getStringAttribute("origName")) {
481 clone->setStringAttribute("origName",node->GetName()) ;
482 }
483
484 // Add to one-time use list and life-time use list
485 clonedMasterNodes.add(*clone) ;
486 if (_owning) {
487 _cloneNodeListOwned->addOwned(std::unique_ptr<RooAbsArg>{clone});
488 } else {
490 }
491 if (_cloneNodeListAll) {
493 }
494 }
495 masterNodesToBeSplit.add(*node) ;
496 }
497
498 RooAbsArg* ReplaceArg = static_cast<RooAbsArg*>(_replaceArgList.FindObject(node->GetName())) ;
499 if (ReplaceArg) {
500 RooAbsArg* substArg = static_cast<RooAbsArg*>(_replaceSubList.At(_replaceArgList.IndexOf(ReplaceArg))) ;
501 if (verbose) {
502 oocoutI(nullptr, ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
503 << "): tree node " << node->GetName() << " will be replaced by " << substArg->GetName() << endl ;
504 }
505
506 // Affix attribute with old name to support name changing server redirect
507 TString nameAttrib("ORIGNAME:") ;
508 nameAttrib.Append(node->GetName()) ;
509 substArg->setAttribute(nameAttrib) ;
510
511 // Add to list
512 masterNodesToBeReplaced.add(*node) ;
513 masterReplacementNodes.add(*substArg) ;
514 }
515 }
516
517 // Find branches that are affected by splitting and must be cloned
518 RooArgSet masterBranchesToBeCloned("masterBranchesToBeCloned") ;
519 for (auto branch : _masterBranchList) {
520
521 // If branch is split itself, don't handle here
522 if (masterNodesToBeSplit.find(branch->GetName())) {
523 if (verbose) {
524 oocoutI(nullptr, ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node " << branch->GetName() << " is already split" << endl ;
525 }
526 continue ;
527 }
528 if (masterNodesToBeReplaced.find(branch->GetName())) {
529 if (verbose) {
530 oocoutI(nullptr, ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node " << branch->GetName() << " is already replaced" << endl ;
531 }
532 continue ;
533 }
534
535 if (branch->dependsOn(masterNodesToBeSplit)) {
536 if (verbose) {
537 oocoutI(nullptr, ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node "
538 << branch->ClassName() << "::" << branch->GetName() << " cloned: depends on a split parameter" << endl ;
539 }
540 masterBranchesToBeCloned.add(*branch) ;
541 } else if (branch->dependsOn(masterNodesToBeReplaced)) {
542 if (verbose) {
543 oocoutI(nullptr, ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node "
544 << branch->ClassName() << "::" << branch->GetName() << " cloned: depends on a replaced parameter" << endl ;
545 }
546 masterBranchesToBeCloned.add(*branch) ;
547 }
548 }
549
550 // Clone branches, changes their names
551 RooAbsArg* cloneTopPdf = nullptr;
552 RooArgSet clonedMasterBranches("clonedMasterBranches") ;
553
554 for (auto branch : masterBranchesToBeCloned) {
555 TString newName(branch->GetName()) ;
556 if (masterCatState) {
557 newName.Append("_") ;
558 newName.Append(masterCatState) ;
559 }
560
561 // Affix attribute with old name to clone to support name changing server redirect
562 RooAbsArg* clone = static_cast<RooAbsArg*>(branch->Clone(newName.Data())) ;
563 clone->removeStringAttribute("factory_tag") ;
564 TString nameAttrib("ORIGNAME:") ;
565 nameAttrib.Append(branch->GetName()) ;
566 clone->setAttribute(nameAttrib) ;
567
568 if (!clone->getStringAttribute("origName")) {
569 clone->setStringAttribute("origName",branch->GetName()) ;
570 }
571
572 clonedMasterBranches.add(*clone) ;
573
574 // Save pointer to clone of top-level pdf
575 if (branch==_masterPdf) cloneTopPdf=(RooAbsArg*)clone ;
576 }
577
578 if (_owning) {
579 _cloneBranchList->addOwned(clonedMasterBranches) ;
580 } else {
581 _cloneBranchList->add(clonedMasterBranches) ;
582 }
583
584 // Reconnect cloned branches to each other and to cloned nodes
585 for (auto branch : clonedMasterBranches) {
586 branch->redirectServers(clonedMasterBranches,false,true) ;
587 branch->redirectServers(clonedMasterNodes,false,true) ;
588 branch->redirectServers(masterReplacementNodes,false,true) ;
589 }
590
591 return cloneTopPdf ? cloneTopPdf : _masterPdf ;
592}
593
594
595////////////////////////////////////////////////////////////////////////////////
596/// Print arguments of customizer, i.e. input p.d.f and input master category (if any)
597
598void RooCustomizer::printArgs(ostream& os) const
599{
600 os << "[ masterPdf=" << _masterPdf->GetName() ;
601 if (_masterCat) {
602 os << " masterCat=" << _masterCat->GetName() ;
603 }
604 os << " ]" ;
605}
606
607
608
609////////////////////////////////////////////////////////////////////////////////
610/// Print customizer configuration details
611
612void RooCustomizer::printMultiline(ostream& os, Int_t /*content*/, bool /*verbose*/, TString indent) const
613{
614 os << indent << "RooCustomizer for " << _masterPdf->GetName() << (_sterile?" (sterile)":"") << endl ;
615
616 Int_t i;
617 Int_t nsplit = _splitArgList.GetSize();
618 if (nsplit>0) {
619 os << indent << " Splitting rules:" << endl ;
620 for (i=0 ; i<nsplit ; i++) {
621 os << indent << " " << _splitArgList.At(i)->GetName() << " is split by " << _splitCatList.At(i)->GetName() << endl ;
622 }
623 }
624
625 Int_t nrepl = _replaceArgList.GetSize() ;
626 if (nrepl>0) {
627 os << indent << " Replacement rules:" << endl ;
628 for (i=0 ; i<nrepl ; i++) {
629 os << indent << " " << _replaceSubList.At(i)->GetName() << " replaces " << _replaceArgList.At(i)->GetName() << endl ;
630 }
631 }
632
633 return ;
634}
635
636
637
638////////////////////////////////////////////////////////////////////////////////
639/// Install the input RooArgSet as container in which all cloned branches
640/// will be stored
641
643{
644 _cloneBranchList = &cloneBranchSet ;
646}
647
648
650 return static_cast<RooAbsPdf&>(*_masterPdf);
651}
652
653
654namespace {
655
656////////////////////////////////////////////////////////////////////////////////
657
658std::string CustIFace::create(RooFactoryWSTool& ft, const char* typeName, const char* instanceName, std::vector<std::string> args)
659{
660 // Check number of arguments
661 if (args.size()<2) {
662 throw string(Form("RooCustomizer::CustIFace::create() ERROR: expect at least 2 arguments for EDIT: the input object and at least one $Replace() rule")) ;
663 }
664
665 if (string(typeName)!="EDIT") {
666 throw string(Form("RooCustomizer::CustIFace::create() ERROR: unknown type requested: %s",typeName)) ;
667 }
668
669 // Check that first arg exists as RooAbsArg
670 RooAbsArg* arg = ft.ws().arg(args[0]) ;
671 if (!arg) {
672 throw string(Form("RooCustomizer::CustIFace::create() ERROR: input RooAbsArg %s does not exist",args[0].c_str())) ;
673 }
674
675 // If name of new object is same as original, execute in sterile mode (i.e no suffixes attached), and rename original nodes in workspace upon import
676 if (args[0]==instanceName) {
677 instanceName=nullptr ;
678 }
679
680 // Create a customizer
681 RooCustomizer cust(*arg,instanceName) ;
682
683 for (unsigned int i=1 ; i<args.size() ; i++) {
684 char buf[1024] ;
685 strlcpy(buf,args[i].c_str(),1024) ;
686 char* sep = strchr(buf,'=') ;
687 if (!sep) {
688 throw string(Form("RooCustomizer::CustIFace::create() ERROR: unknown argument: %s, expect form orig=subst",args[i].c_str())) ;
689 }
690 *sep = 0 ;
691 RooAbsArg* orig = ft.ws().arg(buf) ;
692 RooAbsArg* subst(nullptr) ;
693 if (string(sep+1).find("$REMOVE")==0) {
694
695 // Create a removal dummy ;
697
698 // If removal instructed was annotated with target node, encode these in removal dummy
699 char* sep2 = strchr(sep+1,'(') ;
700 if (sep2) {
701 char buf2[1024] ;
702 strlcpy(buf2,sep2+1,1024) ;
703 char* saveptr ;
704 char* tok = R__STRTOK_R(buf2,",)",&saveptr) ;
705 while(tok) {
706 //cout << "$REMOVE is restricted to " << tok << endl ;
707 subst->setAttribute(Form("REMOVE_FROM_%s",tok)) ;
708 tok = R__STRTOK_R(nullptr,",)",&saveptr) ;
709 }
710 } else {
711 // Otherwise mark as universal removal node
712 subst->setAttribute("REMOVE_ALL") ;
713 }
714
715 } else {
716 subst = ft.ws().arg(sep+1) ;
717 }
718// if (!orig) {
719// throw string(Form("RooCustomizer::CustIFace::create() ERROR: $Replace() input RooAbsArg %s does not exist",buf)) ;
720// }
721// if (!subst) {
722// throw string(Form("RooCustomizer::CustIFace::create() ERROR: $Replace() replacement RooAbsArg %s does not exist",sep+1)) ;
723// }
724 if (orig && subst) {
725 cust.replaceArg(*orig,*subst) ;
726 } else {
727 oocoutW(nullptr,ObjectHandling) << "RooCustomizer::CustIFace::create() WARNING: input or replacement of a replacement operation not found, operation ignored"<< endl ;
728 }
729 }
730
731 // Build the desired edited object
732 RooAbsArg* targ = cust.build(false) ;
733 if (!targ) {
734 throw string(Form("RooCustomizer::CustIFace::create() ERROR in customizer build, object %snot created",instanceName)) ;
735 }
736
737 // Import the object into the workspace
738 if (instanceName) {
739 // Set the desired name of the top level node
740 targ->SetName(instanceName) ;
741 // Now import everything. What we didn't touch gets recycled, everything else was cloned here:
742 ft.ws().import(cust.cloneBranchList(), RooFit::Silence(true), RooFit::RecycleConflictNodes(true), RooFit::NoRecursion(false));
743 } else {
744 ft.ws().import(cust.cloneBranchList(), RooFit::Silence(true), RooFit::RenameConflictNodes("orig",true), RooFit::NoRecursion(true));
745 }
746
747 return string(instanceName?instanceName:targ->GetName()) ;
748}
749
750} // namespace
TObject * clone(const char *newname) const override
Definition RooChi2Var.h:9
#define oocoutW(o, a)
#define oocoutE(o, a)
#define oocoutI(o, a)
static void indent(ostringstream &buf, int indent_level)
char name[80]
Definition TGX11.cxx:110
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
void SetName(const char *name) override
Set the name of the TNamed.
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
const Text_t * getStringAttribute(const Text_t *key) const
Get string attribute mapped under key 'key'.
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
void branchNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=nullptr, bool recurseNonDerived=false) const
Fill supplied list with all branch nodes of the arg tree starting with ourself as top node.
void leafNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=nullptr, bool recurseNonDerived=false) const
Fill supplied list with all leaf nodes of the arg tree, starting with ourself as top node.
Abstract base class for objects that represent a discrete value that can be set from the outside,...
virtual bool setLabel(const char *label, bool printError=true)=0
Change category state by specifying a state name.
A space to attach TBranches.
virtual const char * getCurrentLabel() const
Return label string of current state.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
void useHashMapForFind(bool flag) const
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
RooCustomizer is a factory class to produce clones of a prototype composite PDF object with the same ...
TString _name
Name of this object.
TList _splitArgList
List of RooAbsArgs to be split.
void splitArg(const RooAbsArg &arg, const RooAbsCategory &splitCat)
Split all argument 'arg' into individualized clones for each defined state of 'splitCat'.
void setCloneBranchSet(RooArgSet &cloneBranchSet)
Releases ownership of list of cloned branch nodes.
RooArgSet * _cloneNodeListAll
List of all cloned nodes.
void replaceArg(const RooAbsArg &orig, const RooAbsArg &subst)
Replace any occurrence of arg 'orig' with arg 'subst'.
RooAbsArg * _masterPdf
Pointer to input p.d.f.
bool _owning
If true we own all created components.
TList _replaceSubList
List of replacement RooAbsArgs.
RooAbsArg * build(const char *masterCatState, bool verbose=false)
Build a clone of the prototype executing all registered 'replace' rules and 'split' rules for the mas...
RooArgSet * _cloneBranchList
Pointer to list of cloned branches used.
RooCustomizer(const RooAbsArg &pdf, const RooAbsCategoryLValue &masterCat, RooArgSet &splitLeafListOwned, RooArgSet *splitLeafListAll=nullptr)
Constructor with a prototype and masterCat index category.
RooArgSet _masterBranchList
List of branch nodes.
RooArgSet _masterLeafList
List of leaf nodes.
void initialize()
Initialize the customizer.
RooAbsCategoryLValue * _masterCat
Pointer to input master category.
void splitArgs(const RooArgSet &argSet, const RooAbsCategory &splitCat)
Split all arguments in 'set' into individualized clones for each defined state of 'splitCat'.
void printMultiline(std::ostream &os, Int_t content, bool verbose=false, TString indent="") const
Print customizer configuration details.
RooAbsArg * doBuild(const char *masterCatState, bool verbose)
Back-end implementation of the p.d.f building functionality.
TList _replaceArgList
List of RooAbsArgs to be replaced.
bool _sterile
If true we do not have as associated master category.
RooAbsPdf const & pdf() const
TList _splitCatList
List of categories to be used for above splits.
RooArgSet * _cloneNodeListOwned
List of owned cloned nodes.
void printArgs(std::ostream &os) const
Print arguments of customizer, i.e. input p.d.f and input master category (if any)
virtual std::string create(RooFactoryWSTool &ft, const char *typeName, const char *instanceName, std::vector< std::string > args)=0
Implementation detail of the RooWorkspace.
RooWorkspace & ws()
static void registerSpecial(const char *typeName, RooFactoryWSTool::IFace *iface)
Register foreign special objects in factory.
static RooConstVar & removalDummy()
Create a dummy node used in node-removal operations.
RooAbsArg * arg(RooStringView name) const
Return RooAbsArg with given name. A null pointer is returned if none is found.
bool import(const RooAbsArg &arg, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={})
Import a RooAbsArg object, e.g.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:576
void Add(TObject *obj) override
Definition TList.h:81
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:355
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:439
virtual Int_t IndexOf(const TObject *obj) const
Return index of object in collection.
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:417
const char * Data() const
Definition TString.h:376
TString & Append(const char *cs)
Definition TString.h:572
RooCmdArg RecycleConflictNodes(bool flag=true)
RooCmdArg Silence(bool flag=true)
RooCmdArg NoRecursion(bool flag=true)
RooCmdArg RenameConflictNodes(const char *suffix, bool renameOrigNodes=false)
void(off) SmallVectorTemplateBase< T
void init()
Inspect hardware capabilities, and load the optimal library for RooFit computations.