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