Logo ROOT  
Reference Guide
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 occurence 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 splitLeafs;
59 * RooCustomizer cust(pdf,runblock,splitLeafs);
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, leafs may be split
68 * by any subset of that master category. E.g. if the master category
69 * is 'A x B', leafs 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 (splitLeafs 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 leafs in leaf list. These leafs
90 * must have the name `<split_leaf>_<splitcat_label>` to be picked up. The list
91 * of pre-supplied leafs may be partial, any missing split leafs 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 leafs, 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 leafs instantiated by the first customizer and the link between
103 * the two PDFs is retained.
104 *
105 * ### Customising with pre-defined leafs
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 customisedLeafs;
131 * RooArgSet allLeafs;
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 * allLeafs.add(yield1);
137 * allLeafs.add(yield2);
138 *
139 *
140 * RooCustomizer cust(model, sample, customisedLeafs, &allLeafs);
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 "RooAbsCategoryLValue.h"
153#include "RooAbsCategory.h"
154#include "RooAbsArg.h"
155#include "RooAbsPdf.h"
156#include "RooArgSet.h"
157#include "RooArgList.h"
158#include "RooMsgService.h"
159#include "RooHelpers.h"
160
161#include <iostream>
162#include "strtok.h"
163#include "strlcpy.h"
164
165#include "RooWorkspace.h"
166#include "RooGlobalFunc.h"
167#include "RooConstVar.h"
168#include "RooRealConstant.h"
169
170
171#ifndef _WIN32
172#include <strings.h>
173#endif
174
175
176using namespace std;
177
179;
180
181namespace {
182
183static Int_t init();
184
185Int_t dummy = init() ;
186
187static Int_t init()
188{
191 (void) dummy;
192 return 0 ;
193}
194
195}
196
197////////////////////////////////////////////////////////////////////////////////
198/// Constructor with a prototype and masterCat index category.
199/// Customizers created by this constructor offer both the
200/// replaceArg() and splitArg() functionality.
201/// \param[in] pdf Proto PDF to be customised.
202/// \param[in] masterCat Category to be used for splitting.
203/// \param[in,out] splitLeafs All nodes created in
204/// the customisation process are added to this set.
205/// The user can provide nodes that are *taken*
206/// from the set if they have a name that matches `<parameterNameToBeReplaced>_<category>`.
207/// \note The set needs to own its contents if they are user-provided.
208/// Use *e.g.*
209/// ```
210/// RooArgSet customisedLeafs;
211/// auto yield1 = new RooFormulaVar("yieldSig_BBG1m2T","sigy1","M/3.360779",mass);
212/// customisedLeafs.addOwned(*yield1);
213/// ```
214/// \param[in,out] splitLeafsAll All leafs that are used when customising are collected here.
215/// If this set already contains leaves, they will be used for customising if the names match
216/// as above.
217///
218
220 RooArgSet& splitLeafs, RooArgSet* splitLeafsAll) :
221 TNamed(pdf.GetName(),pdf.GetTitle()),
222 _sterile(kFALSE),
223 _owning(kTRUE),
224 _masterPdf((RooAbsArg*)&pdf),
225 _masterCat((RooAbsCategoryLValue*)&masterCat),
226 _masterBranchList("masterBranchList"),
227 _masterLeafList("masterLeafList"),
228 _internalCloneBranchList("cloneBranchList"),
229 _cloneNodeListAll(splitLeafsAll),
230 _cloneNodeListOwned(&splitLeafs)
231{
233
234 initialize() ;
235}
236
237
238
239////////////////////////////////////////////////////////////////////////////////
240/// Sterile Constructor. Customizers created by this constructor
241/// offer only the replace() method. The supplied 'name' is used as
242/// suffix for any cloned branch nodes
243
245 TNamed(pdf.GetName(),pdf.GetTitle()),
246 _sterile(kTRUE),
247 _owning(kFALSE),
248 _name(name),
249 _masterPdf((RooAbsArg*)&pdf),
250 _masterCat(0),
251 _masterBranchList("masterBranchList"),
252 _masterLeafList("masterLeafList"),
253 _internalCloneBranchList("cloneBranchList"),
254 _cloneNodeListAll(0),
255 _cloneNodeListOwned(0)
256{
258
259 initialize() ;
260}
261
262
263
264
265////////////////////////////////////////////////////////////////////////////////
266/// Initialize the customizer
267
269{
272}
273
274
275
276////////////////////////////////////////////////////////////////////////////////
277/// Destructor
278
280{
281
282}
283
284
285
286
287////////////////////////////////////////////////////////////////////////////////
288/// Split all arguments in 'set' into individualized clones for each
289/// defined state of 'splitCat'. The 'splitCats' category must be
290/// subset of or equal to the master category supplied in the
291/// customizer constructor.
292///
293/// Splitting is only available on customizers created with a master index category
294
295void RooCustomizer::splitArgs(const RooArgSet& set, const RooAbsCategory& splitCat)
296{
297 if (_sterile) {
298 coutE(InputArguments) << "RooCustomizer::splitArgs(" << _name
299 << ") ERROR cannot set spitting rules on this sterile customizer" << endl ;
300 return ;
301 }
302
303 for (auto arg : set) {
304 splitArg(*arg,splitCat) ;
305 }
306}
307
308
309
310////////////////////////////////////////////////////////////////////////////////
311/// Split all argument 'arg' into individualized clones for each
312/// defined state of 'splitCat'. The 'splitCats' category must be
313/// subset of or equal to the master category supplied in the
314/// customizer constructor.
315///
316/// Splitting is only available on customizers created with a master index category
317
318void RooCustomizer::splitArg(const RooAbsArg& arg, const RooAbsCategory& splitCat)
319{
320 if (_splitArgList.FindObject(arg.GetName())) {
321 coutE(InputArguments) << "RooCustomizer(" << GetName() << ") ERROR: multiple splitting rules defined for "
322 << arg.GetName() << " only using first rule" << endl ;
323 return ;
324 }
325
326 if (_sterile) {
327 coutE(InputArguments) << "RooCustomizer::splitArg(" << _name
328 << ") ERROR cannot set spitting rules on this sterile customizer" << endl ;
329 return ;
330 }
331
332 _splitArgList.Add((RooAbsArg*)&arg) ;
333 _splitCatList.Add((RooAbsCategory*)&splitCat) ;
334}
335
336
337
338////////////////////////////////////////////////////////////////////////////////
339/// Replace any occurence of arg 'orig' with arg 'subst'
340
341void RooCustomizer::replaceArg(const RooAbsArg& orig, const RooAbsArg& subst)
342{
343 if (_replaceArgList.FindObject(orig.GetName())) {
344 coutE(InputArguments) << "RooCustomizer(" << GetName() << ") ERROR: multiple replacement rules defined for "
345 << orig.GetName() << " only using first rule" << endl ;
346 return ;
347 }
348
349 _replaceArgList.Add((RooAbsArg*)&orig) ;
350 _replaceSubList.Add((RooAbsArg*)&subst) ;
351}
352
353
354
355////////////////////////////////////////////////////////////////////////////////
356/// Build a clone of the prototype executing all registered 'replace' rules.
357/// If verbose is set, a message is printed for each leaf or branch node
358/// modification. The returned head node owns all cloned branch nodes
359/// that were created in the cloning process.
360
362{
363 // Execute build
364 RooAbsArg* ret = doBuild(_name.Length()>0?_name.Data():0,verbose) ;
365
366 // Make root object own all cloned nodes
367
368 // First make list of all objects that were created
369 RooArgSet allOwned ;
371 allOwned.add(*_cloneNodeListOwned) ;
372 }
373 allOwned.add(*_cloneBranchList) ;
374
375 // Remove head node from list
376 allOwned.remove(*ret) ;
377
378 // If list with owned objects is not empty, assign
379 // head node as owner
380 if (allOwned.getSize()>0) {
381 ret->addOwnedComponents(allOwned) ;
382 }
383
384 return ret ;
385}
386
387
388
389////////////////////////////////////////////////////////////////////////////////
390/// Build a clone of the prototype executing all registered 'replace'
391/// rules and 'split' rules for the masterCat state named
392/// 'masterCatState'. If verbose is set a message is printed for
393/// each leaf or branch node modification. The returned composite arg
394/// is owned by the customizer. This function cannot be called on
395/// customizer build with the sterile constructor.
396
397RooAbsArg* RooCustomizer::build(const char* masterCatState, Bool_t verbose)
398{
399 if (_sterile) {
400 coutE(InputArguments) << "RooCustomizer::build(" << _name
401 << ") ERROR cannot use leaf spitting build() on this sterile customizer" << endl ;
402 return 0 ;
403 }
404
405 // Set masterCat to given state
406 if (_masterCat->setLabel(masterCatState)) {
407 coutE(InputArguments) << "RooCustomizer::build(" << _masterPdf->GetName() << "): ERROR label '" << masterCatState
408 << "' not defined for master splitting category " << _masterCat->GetName() << endl ;
409 return 0 ;
410 }
411
412 return doBuild(masterCatState,verbose) ;
413}
414
415
416
417////////////////////////////////////////////////////////////////////////////////
418/// Back-end implementation of the p.d.f building functionality
419
420RooAbsArg* RooCustomizer::doBuild(const char* masterCatState, Bool_t verbose)
421{
422 // Find nodes that must be split according to provided description, Clone nodes, change their names
423 RooArgSet masterNodesToBeSplit("masterNodesToBeSplit") ;
424 RooArgSet masterNodesToBeReplaced("masterNodesToBeReplaced") ;
425 RooArgSet masterReplacementNodes("masterReplacementNodes") ;
426 RooArgSet clonedMasterNodes("clonedMasterNodes") ;
427
428
429 RooArgSet nodeList(_masterLeafList) ;
430 nodeList.add(_masterBranchList) ;
431
432 // cout << "loop over " << nodeList.getSize() << " nodes" << endl ;
433 for (auto node : nodeList) {
434 RooAbsArg* theSplitArg = !_sterile?(RooAbsArg*) _splitArgList.FindObject(node->GetName()):0 ;
435 if (theSplitArg) {
437 if (verbose) {
438 coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
439 << "): tree node " << node->GetName() << " is split by category " << splitCat->GetName() << endl ;
440 }
441
442 TString newName(node->GetName()) ;
443 if (masterCatState) {
444 newName.Append("_") ;
445 newName.Append(splitCat->getCurrentLabel()) ;
446 }
447
448 // Check if this node instance already exists
449 RooAbsArg* specNode = _cloneNodeListAll ? _cloneNodeListAll->find(newName) : _cloneNodeListOwned->find(newName) ;
450 if (specNode) {
451
452 // Copy instance to one-time use list for this build
453 clonedMasterNodes.add(*specNode) ;
454 if (verbose) {
455 coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
456 << ") Adding existing node specialization " << newName << " to clonedMasterNodes" << endl ;
457 }
458
459 // Affix attribute with old name to clone to support name changing server redirect
460 TString nameAttrib("ORIGNAME:") ;
461 nameAttrib.Append(node->GetName()) ;
462 specNode->setAttribute(nameAttrib) ;
463
464 if (!specNode->getStringAttribute("origName")) {
465 specNode->setStringAttribute("origName",node->GetName()) ;
466 }
467
468
469
470 } else {
471
472 if (node->isDerived()) {
473 coutW(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
474 << "): WARNING: branch node " << node->GetName() << " is split but has no pre-defined specializations" << endl ;
475 }
476
477 TString newTitle(node->GetTitle()) ;
478 newTitle.Append(" (") ;
479 newTitle.Append(splitCat->getCurrentLabel()) ;
480 newTitle.Append(")") ;
481
482 // Create a new clone
483 RooAbsArg* clone = (RooAbsArg*) node->Clone(newName.Data()) ;
484 clone->setStringAttribute("factory_tag",0) ;
485 clone->SetTitle(newTitle) ;
486
487 // Affix attribute with old name to clone to support name changing server redirect
488 TString nameAttrib("ORIGNAME:") ;
489 nameAttrib.Append(node->GetName()) ;
490 clone->setAttribute(nameAttrib) ;
491
492 if (!clone->getStringAttribute("origName")) {
493 clone->setStringAttribute("origName",node->GetName()) ;
494 }
495
496 // Add to one-time use list and life-time use list
497 clonedMasterNodes.add(*clone) ;
498 if (_owning) {
500 } else {
501 _cloneNodeListOwned->add(*clone) ;
502 }
503 if (_cloneNodeListAll) {
504 _cloneNodeListAll->add(*clone) ;
505 }
506 }
507 masterNodesToBeSplit.add(*node) ;
508 }
509
510 RooAbsArg* ReplaceArg = (RooAbsArg*) _replaceArgList.FindObject(node->GetName()) ;
511 if (ReplaceArg) {
512 RooAbsArg* substArg = (RooAbsArg*) _replaceSubList.At(_replaceArgList.IndexOf(ReplaceArg)) ;
513 if (verbose) {
514 coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName()
515 << "): tree node " << node->GetName() << " will be replaced by " << substArg->GetName() << endl ;
516 }
517
518 // Affix attribute with old name to support name changing server redirect
519 TString nameAttrib("ORIGNAME:") ;
520 nameAttrib.Append(node->GetName()) ;
521 substArg->setAttribute(nameAttrib) ;
522
523 // Add to list
524 masterNodesToBeReplaced.add(*node) ;
525 masterReplacementNodes.add(*substArg) ;
526 }
527 }
528
529 // Find branches that are affected by splitting and must be cloned
530 RooArgSet masterBranchesToBeCloned("masterBranchesToBeCloned") ;
531 for (auto branch : _masterBranchList) {
532
533 // If branch is split itself, don't handle here
534 if (masterNodesToBeSplit.find(branch->GetName())) {
535 if (verbose) {
536 coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node " << branch->GetName() << " is already split" << endl ;
537 }
538 continue ;
539 }
540 if (masterNodesToBeReplaced.find(branch->GetName())) {
541 if (verbose) {
542 coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node " << branch->GetName() << " is already replaced" << endl ;
543 }
544 continue ;
545 }
546
547 if (branch->dependsOn(masterNodesToBeSplit)) {
548 if (verbose) {
549 coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node "
550 << branch->IsA()->GetName() << "::" << branch->GetName() << " cloned: depends on a split parameter" << endl ;
551 }
552 masterBranchesToBeCloned.add(*branch) ;
553 } else if (branch->dependsOn(masterNodesToBeReplaced)) {
554 if (verbose) {
555 coutI(ObjectHandling) << "RooCustomizer::build(" << _masterPdf->GetName() << ") Branch node "
556 << branch->IsA()->GetName() << "::" << branch->GetName() << " cloned: depends on a replaced parameter" << endl ;
557 }
558 masterBranchesToBeCloned.add(*branch) ;
559 }
560 }
561
562 // Clone branches, changes their names
563 RooAbsArg* cloneTopPdf = 0;
564 RooArgSet clonedMasterBranches("clonedMasterBranches") ;
565
566 for (auto branch : masterBranchesToBeCloned) {
567 TString newName(branch->GetName()) ;
568 if (masterCatState) {
569 newName.Append("_") ;
570 newName.Append(masterCatState) ;
571 }
572
573 // Affix attribute with old name to clone to support name changing server redirect
574 RooAbsArg* clone = (RooAbsArg*) branch->Clone(newName.Data()) ;
575 clone->setStringAttribute("factory_tag",0) ;
576 TString nameAttrib("ORIGNAME:") ;
577 nameAttrib.Append(branch->GetName()) ;
578 clone->setAttribute(nameAttrib) ;
579
580 if (!clone->getStringAttribute("origName")) {
581 clone->setStringAttribute("origName",branch->GetName()) ;
582 }
583
584 clonedMasterBranches.add(*clone) ;
585
586 // Save pointer to clone of top-level pdf
587 if (branch==_masterPdf) cloneTopPdf=(RooAbsArg*)clone ;
588 }
589
590 if (_owning) {
591 _cloneBranchList->addOwned(clonedMasterBranches) ;
592 } else {
593 _cloneBranchList->add(clonedMasterBranches) ;
594 }
595
596 // Reconnect cloned branches to each other and to cloned nodess
597 for (auto branch : clonedMasterBranches) {
598 branch->redirectServers(clonedMasterBranches,kFALSE,kTRUE) ;
599 branch->redirectServers(clonedMasterNodes,kFALSE,kTRUE) ;
600 branch->redirectServers(masterReplacementNodes,kFALSE,kTRUE) ;
601 }
602
603 return cloneTopPdf ? cloneTopPdf : _masterPdf ;
604}
605
606
607////////////////////////////////////////////////////////////////////////////////
608/// Print name of customizer
609
610void RooCustomizer::printName(ostream& os) const
611{
612 os << GetName() ;
613}
614
615
616////////////////////////////////////////////////////////////////////////////////
617/// Print title of customizer
618
619void RooCustomizer::printTitle(ostream& os) const
620{
621 os << GetTitle() ;
622}
623
624
625////////////////////////////////////////////////////////////////////////////////
626/// Print class name of customizer
627
628void RooCustomizer::printClassName(ostream& os) const
629{
630 os << IsA()->GetName() ;
631}
632
633
634////////////////////////////////////////////////////////////////////////////////
635/// Print arguments of customizer, i.e. input p.d.f and input master category (if any)
636
637void RooCustomizer::printArgs(ostream& os) const
638{
639 os << "[ masterPdf=" << _masterPdf->GetName() ;
640 if (_masterCat) {
641 os << " masterCat=" << _masterCat->GetName() ;
642 }
643 os << " ]" ;
644}
645
646
647
648////////////////////////////////////////////////////////////////////////////////
649/// Print customizer configuration details
650
651void RooCustomizer::printMultiline(ostream& os, Int_t /*content*/, Bool_t /*verbose*/, TString indent) const
652{
653 os << indent << "RooCustomizer for " << _masterPdf->GetName() << (_sterile?" (sterile)":"") << endl ;
654
655 Int_t i, nsplit = _splitArgList.GetSize() ;
656 if (nsplit>0) {
657 os << indent << " Splitting rules:" << endl ;
658 for (i=0 ; i<nsplit ; i++) {
659 os << indent << " " << _splitArgList.At(i)->GetName() << " is split by " << _splitCatList.At(i)->GetName() << endl ;
660 }
661 }
662
663 Int_t nrepl = _replaceArgList.GetSize() ;
664 if (nrepl>0) {
665 os << indent << " Replacement rules:" << endl ;
666 for (i=0 ; i<nrepl ; i++) {
667 os << indent << " " << _replaceSubList.At(i)->GetName() << " replaces " << _replaceArgList.At(i)->GetName() << endl ;
668 }
669 }
670
671 return ;
672}
673
674
675
676////////////////////////////////////////////////////////////////////////////////
677/// Install the input RooArgSet as container in which all cloned branches
678/// will be stored
679
681{
682 _cloneBranchList = &cloneBranchSet ;
684}
685
686
687
688
689////////////////////////////////////////////////////////////////////////////////
690
691std::string RooCustomizer::CustIFace::create(RooFactoryWSTool& ft, const char* typeName, const char* instanceName, std::vector<std::string> args)
692{
693 // Check number of arguments
694 if (args.size()<2) {
695 throw string(Form("RooCustomizer::CustIFace::create() ERROR: expect at least 2 arguments for EDIT: the input object and at least one $Replace() rule")) ;
696 }
697
698 if (string(typeName)!="EDIT") {
699 throw string(Form("RooCustomizer::CustIFace::create() ERROR: unknown type requested: %s",typeName)) ;
700 }
701
702 // Check that first arg exists as RooAbsArg
703 RooAbsArg* arg = ft.ws().arg(args[0].c_str()) ;
704 if (!arg) {
705 throw string(Form("RooCustomizer::CustIFace::create() ERROR: input RooAbsArg %s does not exist",args[0].c_str())) ;
706 }
707
708 // 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
709 if (args[0]==instanceName) {
710 instanceName=0 ;
711 }
712
713 // Create a customizer
714 RooCustomizer cust(*arg,instanceName) ;
715
716 for (unsigned int i=1 ; i<args.size() ; i++) {
717 char buf[1024] ;
718 strlcpy(buf,args[i].c_str(),1024) ;
719 char* sep = strchr(buf,'=') ;
720 if (!sep) {
721 throw string(Form("RooCustomizer::CustIFace::create() ERROR: unknown argument: %s, expect form orig=subst",args[i].c_str())) ;
722 }
723 *sep = 0 ;
724 RooAbsArg* orig = ft.ws().arg(buf) ;
725 RooAbsArg* subst(0) ;
726 if (string(sep+1).find("$REMOVE")==0) {
727
728 // Create a removal dummy ;
730
731 // If removal instructed was annotated with target node, encode these in removal dummy
732 char* sep2 = strchr(sep+1,'(') ;
733 if (sep2) {
734 char buf2[1024] ;
735 strlcpy(buf2,sep2+1,1024) ;
736 char* saveptr ;
737 char* tok = R__STRTOK_R(buf2,",)",&saveptr) ;
738 while(tok) {
739 //cout << "$REMOVE is restricted to " << tok << endl ;
740 subst->setAttribute(Form("REMOVE_FROM_%s",tok)) ;
741 tok = R__STRTOK_R(0,",)",&saveptr) ;
742 }
743 } else {
744 // Otherwise mark as universal removal node
745 subst->setAttribute("REMOVE_ALL") ;
746 }
747
748 } else {
749 subst = ft.ws().arg(sep+1) ;
750 }
751// if (!orig) {
752// throw string(Form("RooCustomizer::CustIFace::create() ERROR: $Replace() input RooAbsArg %s does not exist",buf)) ;
753// }
754// if (!subst) {
755// throw string(Form("RooCustomizer::CustIFace::create() ERROR: $Replace() replacement RooAbsArg %s does not exist",sep+1)) ;
756// }
757 if (orig && subst) {
758 cust.replaceArg(*orig,*subst) ;
759 } else {
760 oocoutW((TObject*)0,ObjectHandling) << "RooCustomizer::CustIFace::create() WARNING: input or replacement of a replacement operation not found, operation ignored"<< endl ;
761 }
762 }
763
764 // Build the desired edited object
765 RooAbsArg* targ = cust.build(kFALSE) ;
766 if (!targ) {
767 throw string(Form("RooCustomizer::CustIFace::create() ERROR in customizer build, object %snot created",instanceName)) ;
768 }
769
770 // Import the object into the workspace
771 if (instanceName) {
772 // Set the desired name of the top level node
773 targ->SetName(instanceName) ;
774 // Now import everything. What we didn't touch gets recycled, everything else was cloned here:
776 } else {
778 }
779
780 return string(instanceName?instanceName:targ->GetName()) ;
781}
#define coutI(a)
Definition: RooMsgService.h:30
#define oocoutW(o, a)
Definition: RooMsgService.h:47
#define coutW(a)
Definition: RooMsgService.h:32
#define coutE(a)
Definition: RooMsgService.h:33
const Bool_t kFALSE
Definition: RtypesCore.h:101
const Bool_t kTRUE
Definition: RtypesCore.h:100
#define ClassImp(name)
Definition: Rtypes.h:375
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:2447
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition: RooAbsArg.h:78
TObject * Clone(const char *newname=0) const override
Make a clone of an object using the Streamer facility.
Definition: RooAbsArg.h:90
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
Definition: RooAbsArg.cxx:314
void leafNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=0, Bool_t recurseNonDerived=kFALSE) const
Fill supplied list with all leaf nodes of the arg tree, starting with ourself as top node.
Definition: RooAbsArg.cxx:500
void SetName(const char *name) override
Set the name of the TNamed.
Definition: RooAbsArg.cxx:2399
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
Definition: RooAbsArg.cxx:2275
const Text_t * getStringAttribute(const Text_t *key) const
Get string attribute mapped under key 'key'.
Definition: RooAbsArg.cxx:327
void setAttribute(const Text_t *name, Bool_t value=kTRUE)
Set (default) or clear a named boolean attribute of this object.
Definition: RooAbsArg.cxx:282
void branchNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=0, Bool_t recurseNonDerived=kFALSE) const
Fill supplied list with all branch nodes of the arg tree starting with ourself as top node.
Definition: RooAbsArg.cxx:511
RooAbsCategoryLValue is the common abstract base class for objects that represent a discrete value th...
virtual bool setLabel(const char *label, Bool_t printError=kTRUE)=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_t add(const RooAbsArg &var, Bool_t silent=kFALSE)
Add the specified argument to list.
Int_t getSize() const
Return the number of elements in the collection.
virtual Bool_t addOwned(RooAbsArg &var, Bool_t silent=kFALSE)
Add an argument and transfer the ownership to the collection.
void useHashMapForFind(bool flag) const
virtual Bool_t remove(const RooAbsArg &var, Bool_t silent=kFALSE, Bool_t matchByNameOnly=kFALSE)
Remove the specified argument from our list.
RooAbsArg * find(const char *name) const
Find object with given name in list.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgSet.h:57
Factory interface.
Definition: RooCustomizer.h:80
std::string create(RooFactoryWSTool &ft, const char *typeName, const char *instanceName, std::vector< std::string > args) override
RooCustomizer is a factory class to produce clones of a prototype composite PDF object with the same ...
Definition: RooCustomizer.h:35
void printTitle(std::ostream &os) const override
Print title of customizer.
TString _name
Name of this object.
Definition: RooCustomizer.h:95
Bool_t _sterile
If true we do not have as associated master category.
Definition: RooCustomizer.h:93
TList _splitArgList
List of RooAbsArgs to be split.
Definition: RooCustomizer.h:97
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.
TClass * IsA() const override
void printName(std::ostream &os) const override
Print name of customizer.
void replaceArg(const RooAbsArg &orig, const RooAbsArg &subst)
Replace any occurence of arg 'orig' with arg 'subst'.
RooAbsArg * _masterPdf
Pointer to input p.d.f.
TList _replaceSubList
List of replacement RooAbsArgs.
void printArgs(std::ostream &os) const override
Print arguments of customizer, i.e. input p.d.f and input master category (if any)
const RooArgSet & cloneBranchList() const
Return list of cloned branch nodes.
Definition: RooCustomizer.h:56
RooArgSet * _cloneBranchList
Pointer to list of cloned branches used.
~RooCustomizer() override
Destructor.
RooCustomizer(const RooAbsArg &pdf, const RooAbsCategoryLValue &masterCat, RooArgSet &splitLeafListOwned, RooArgSet *splitLeafListAll=0)
Constructor with a prototype and masterCat index category.
void printMultiline(std::ostream &os, Int_t content, Bool_t verbose=kFALSE, TString indent="") const override
Print customizer configuration details.
RooArgSet _masterBranchList
List of branch nodes.
RooAbsArg * doBuild(const char *masterCatState, Bool_t verbose)
Back-end implementation of the p.d.f building functionality.
RooArgSet _masterLeafList
List of leaf nodes.
RooArgSet _internalCloneBranchList
List of branches of internal clone.
void initialize()
Initialize the customizer.
RooAbsCategoryLValue * _masterCat
Pointer to input master category.
void printClassName(std::ostream &os) const override
Print class name of customizer.
Bool_t _owning
If true we own all created components.
Definition: RooCustomizer.h:94
void splitArgs(const RooArgSet &argSet, const RooAbsCategory &splitCat)
Split all arguments in 'set' into individualized clones for each defined state of 'splitCat'.
RooAbsArg * build(const char *masterCatState, Bool_t verbose=kFALSE)
Build a clone of the prototype executing all registered 'replace' rules and 'split' rules for the mas...
TList _replaceArgList
List of RooAbsArgs to be replaced.
TList _splitCatList
List of categories to be used for above splits.
Definition: RooCustomizer.h:98
RooArgSet * _cloneNodeListOwned
List of owned cloned nodes.
RooFactoryWSTool is a class similar to TTree::MakeClass() that generates skeleton code for RooAbsPdf ...
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.
Bool_t import(const RooAbsArg &arg, const RooCmdArg &arg1=RooCmdArg(), const RooCmdArg &arg2=RooCmdArg(), const RooCmdArg &arg3=RooCmdArg(), const RooCmdArg &arg4=RooCmdArg(), const RooCmdArg &arg5=RooCmdArg(), const RooCmdArg &arg6=RooCmdArg(), const RooCmdArg &arg7=RooCmdArg(), const RooCmdArg &arg8=RooCmdArg(), const RooCmdArg &arg9=RooCmdArg())
Import a RooAbsArg object, e.g.
RooAbsArg * arg(RooStringView name) const
Return RooAbsArg with given name. A null pointer is returned if none is found.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:184
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition: TList.cxx:578
void Add(TObject *obj) override
Definition: TList.h:87
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition: TList.cxx:357
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:164
const char * GetName() const override
Returns name of object.
Definition: TNamed.h:47
const char * GetTitle() const override
Returns title of object.
Definition: TNamed.h:48
Mother of all ROOT objects.
Definition: TObject.h:37
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:359
virtual Int_t IndexOf(const TObject *obj) const
Return index of object in collection.
Basic string class.
Definition: TString.h:136
Ssiz_t Length() const
Definition: TString.h:410
const char * Data() const
Definition: TString.h:369
TString & Append(const char *cs)
Definition: TString.h:564
RooCmdArg NoRecursion(Bool_t flag=kTRUE)
RooCmdArg RecycleConflictNodes(Bool_t flag=kTRUE)
RooCmdArg RenameConflictNodes(const char *suffix, Bool_t renameOrigNodes=kFALSE)
RooCmdArg Silence(Bool_t flag=kTRUE)
void(off) SmallVectorTemplateBase< T
void init()
Inspect hardware capabilities, and load the optimal library for RooFit computations.
@ InputArguments
Definition: RooGlobalFunc.h:64
@ ObjectHandling
Definition: RooGlobalFunc.h:64