Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooFactoryWSTool.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 \file RooFactoryWSTool.cxx
19 \class RooFactoryWSTool
20 \ingroup Roofitcore
21 
22 RooFactoryWSTool is a clase like TTree::MakeClass() that generates
23 skeleton code for RooAbsPdf and RooAbsReal functions given
24 a list of input parameter names. The factory can also compile
25 the generated code on the fly, and on request also immediate
26 instantiate objects.
27 **/
28 
29 #include "RooFit.h"
30 
31 #include "RooFactoryWSTool.h"
32 #include "RooAbsReal.h"
33 #include "RooAbsCategory.h"
34 #include "RooArgList.h"
35 #include "RooRealVar.h"
36 #include "RooCategory.h"
37 #include "RooMsgService.h"
38 #include "RooWorkspace.h"
39 #include "TInterpreter.h"
40 #include "TEnum.h"
41 #include "RooAbsPdf.h"
42 #include "RooGaussian.h"
43 #include <fstream>
44 #include "RooGlobalFunc.h"
45 #include "RooDataSet.h"
46 #include "RooDataHist.h"
47 #include "RooAddPdf.h"
48 #include "RooProdPdf.h"
49 #include "RooSimultaneous.h"
50 #include "RooFFTConvPdf.h"
51 #include "RooNumConvPdf.h"
52 #include "RooResolutionModel.h"
53 #include "RooProduct.h"
54 #include "RooAddition.h"
55 #include "RooChi2Var.h"
56 #include "RooNLLVar.h"
57 #include "RooRealSumPdf.h"
58 #include "RooConstVar.h"
59 #include "RooDerivative.h"
60 #include "RooStringVar.h"
61 #include "TROOT.h"
62 
63 using namespace RooFit ;
64 using namespace std ;
65 
66 #define BUFFER_SIZE 64000
67 
68 ClassImp(RooFactoryWSTool);
69 ;
70 
71 RooFactoryWSTool* RooFactoryWSTool::_of = 0 ;
72 map<string,RooFactoryWSTool::IFace*>* RooFactoryWSTool::_hooks=0 ;
73 
74 static Int_t init();
75 
76 static Int_t dummy = init() ;
77 
78 static Int_t init()
79 {
80  RooFactoryWSTool::IFace* iface = new RooFactoryWSTool::SpecialsIFace ;
81 
82  // Operator p.d.f.s
83  RooFactoryWSTool::registerSpecial("SUM",iface) ;
84  RooFactoryWSTool::registerSpecial("RSUM",iface) ;
85  RooFactoryWSTool::registerSpecial("ASUM",iface) ;
86  RooFactoryWSTool::registerSpecial("PROD",iface) ;
87  RooFactoryWSTool::registerSpecial("SIMUL",iface) ;
88  RooFactoryWSTool::registerSpecial("EXPR",iface) ;
89  RooFactoryWSTool::registerSpecial("FCONV",iface) ;
90  RooFactoryWSTool::registerSpecial("NCONV",iface) ;
91 
92  // Operator functions
93  RooFactoryWSTool::registerSpecial("sum",iface) ;
94  RooFactoryWSTool::registerSpecial("prod",iface) ;
95  RooFactoryWSTool::registerSpecial("expr",iface) ;
96  RooFactoryWSTool::registerSpecial("nconv",iface) ;
97 
98  // Test statistics
99  RooFactoryWSTool::registerSpecial("nll",iface) ;
100  RooFactoryWSTool::registerSpecial("chi2",iface) ;
101  RooFactoryWSTool::registerSpecial("profile",iface) ;
102 
103  // Integration and derivation
104  RooFactoryWSTool::registerSpecial("int",iface) ;
105  RooFactoryWSTool::registerSpecial("deriv",iface) ;
106  RooFactoryWSTool::registerSpecial("cdf",iface) ;
107  RooFactoryWSTool::registerSpecial("PROJ",iface) ;
108 
109  // Miscellaneous
110  RooFactoryWSTool::registerSpecial("dataobs",iface) ;
111  RooFactoryWSTool::registerSpecial("set",iface) ;
112 
113  (void) dummy;
114  return 0 ;
115 }
116 
117 
118 #ifndef _WIN32
119 #include <strings.h>
120 #endif
121 
122 
123 
124 ////////////////////////////////////////////////////////////////////////////////
125 
126 RooFactoryWSTool::RooFactoryWSTool(RooWorkspace& inws) : _ws(&inws), _errorCount(0), _autoClassPostFix("")
127 
128 {
129  // Default constructor
130 }
131 
132 
133 
134 ////////////////////////////////////////////////////////////////////////////////
135 /// Destructor
136 
137 RooFactoryWSTool::~RooFactoryWSTool()
138 {
139 }
140 
141 
142 
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 /// Low-level factory interface for creating a RooRealVar with a given range and initial value
146 
147 RooRealVar* RooFactoryWSTool::createVariable(const char* name, Double_t xmin, Double_t xmax)
148 {
149  // First check if variable already exists
150  if (_ws->var(name)) {
151  coutE(ObjectHandling) << "RooFactoryWSTool::createFactory() ERROR: variable with name '" << name << "' already exists" << endl ;
152  logError() ;
153  return 0 ;
154  }
155 
156  // Create variable
157  RooRealVar var(name,name,xmin,xmax) ;
158 
159  // Put in workspace
160  if (_ws->import(var,Silence())) logError() ;
161 
162  return _ws->var(name) ;
163 }
164 
165 
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// Low-level factory interface for creating a RooCategory with a given list of state names. The State name list
169 /// can be of the form 'name1,name2,name3' or of the form 'name1=id1,name2=id2,name3=id3'
170 
171 RooCategory* RooFactoryWSTool::createCategory(const char* name, const char* stateNameList)
172 {
173  // Create variable
174  RooCategory cat(name,name) ;
175 
176  // Add listed state names
177  if (stateNameList) {
178  const size_t tmpSize = strlen(stateNameList)+1;
179  char *tmp = new char[tmpSize] ;
180  strlcpy(tmp,stateNameList,tmpSize) ;
181  char* save ;
182  char* tok = R__STRTOK_R(tmp,",",&save) ;
183  while(tok) {
184  char* sep = strchr(tok,'=') ;
185  if (sep) {
186  *sep = 0 ;
187  Int_t id = atoi(sep+1) ;
188  cat.defineType(tok,id) ;
189  *sep = '=' ;
190  } else {
191  cat.defineType(tok) ;
192  }
193  tok = R__STRTOK_R(0,",",&save) ;
194  }
195  delete[] tmp ;
196  }
197 
198  cat.setStringAttribute("factory_tag",Form("%s[%s]",name,stateNameList)) ;
199 
200  // Put in workspace
201  if (_ws->import(cat,Silence())) logError() ;
202 
203  return _ws->cat(name) ;
204 }
205 
206 namespace {
207  static bool isEnum(const char* classname) {
208  // Returns true if given type is an enum
209  ClassInfo_t* cls = gInterpreter->ClassInfo_Factory(classname);
210  long property = gInterpreter->ClassInfo_Property(cls);
211  gInterpreter->ClassInfo_Delete(cls);
212  return (property&kIsEnum);
213  }
214 
215 
216  static bool isValidEnumValue(const char* enumName, const char* enumConstantName) {
217  // Returns true if given type is an enum
218 
219  if (!enumName) return false;
220 
221  auto theEnum = TEnum::GetEnum(enumName);
222  if (!enumName) return false;
223 
224  // Attempt 1: Enum constant name as is
225  if (theEnum->GetConstant(enumConstantName)) return true;
226  // Attempt 2: Remove the scope preceding the enum constant name
227  auto tmp = strstr(enumConstantName, "::");
228  if (tmp) {
229  auto enumConstantNameNoScope = tmp+2;
230  if (theEnum->GetConstant(enumConstantNameNoScope)) return true;
231  }
232 
233  return false;
234  }
235 
236  static pair<list<string>,unsigned int> ctorArgs(const char* classname, UInt_t nMinArg) {
237  // Utility function for RooFactoryWSTool. Return arguments of 'first' non-default, non-copy constructor of any RooAbsArg
238  // derived class. Only constructors that start with two 'const char*' arguments (for name and title) are considered
239  // The returned object contains
240 
241  Int_t nreq(0);
242  list<string> ret;
243 
244  ClassInfo_t* cls = gInterpreter->ClassInfo_Factory(classname);
245  MethodInfo_t* func = gInterpreter->MethodInfo_Factory(cls);
246  while(gInterpreter->MethodInfo_Next(func)) {
247  ret.clear();
248  nreq=0;
249 
250  // Find 'the' constructor
251 
252  // Skip non-public methods
253  if (!(gInterpreter->MethodInfo_Property(func) & kIsPublic)) {
254  continue;
255  }
256 
257  // Return type must be class name
258  if (string(classname) != gInterpreter->MethodInfo_TypeName(func)) {
259  continue;
260  }
261 
262  // Skip default constructor
263  int nargs = gInterpreter->MethodInfo_NArg(func);
264  if (nargs==0 || nargs==gInterpreter->MethodInfo_NDefaultArg(func)) {
265  continue;
266  }
267 
268  MethodArgInfo_t* arg = gInterpreter->MethodArgInfo_Factory(func);
269  while (gInterpreter->MethodArgInfo_Next(arg)) {
270  // Require that first two arguments are of type const char*
271  const char* argTypeName = gInterpreter->MethodArgInfo_TypeName(arg);
272  if (nreq<2 && ((string("char*") != argTypeName
273  && !(gInterpreter->MethodArgInfo_Property(arg) & kIsConstPointer))
274  && string("const char*") != argTypeName)) {
275  continue ;
276  }
277  ret.push_back(argTypeName) ;
278  if(!gInterpreter->MethodArgInfo_DefaultValue(arg)) nreq++;
279  }
280  gInterpreter->MethodArgInfo_Delete(arg);
281 
282  // Check that the number of required arguments is at least nMinArg
283  if (ret.size()<nMinArg) {
284  continue;
285  }
286 
287  break;
288  }
289  gInterpreter->MethodInfo_Delete(func);
290  gInterpreter->ClassInfo_Delete(cls);
291  return pair<list<string>,unsigned int>(ret,nreq);
292  }
293 }
294 
295 ////////////////////////////////////////////////////////////////////////////////
296 /// Low-level factory interface for creating a RooAbsPdf of a given class with a given list of input variables
297 /// The variable list varList should be of the form "a,b,c" where the interpretation of the argument is
298 /// dependent on the p.d.f. Set and List arguments can be passed by substituting a single argument with
299 /// the form (a,b,c), i.e. one can set varList to "x,(a0,a1,a2)" to pass a RooAbsReal and a RooArgSet as arguments.
300 
301 RooAbsArg* RooFactoryWSTool::createArg(const char* className, const char* objName, const char* varList)
302 {
303  // Find class in ROOT class table
304  TClass* tc = resolveClassName(className);
305  if (!tc) {
306  coutE(ObjectHandling) << "RooFactoryWSTool::createArg() ERROR class " << className << " not found in factory alias table, nor in ROOT class table" << endl;
307  logError();
308  return 0;
309  }
310 
311  className = tc->GetName();
312 
313  // Check that class inherits from RooAbsPdf
314  if (!tc->InheritsFrom(RooAbsArg::Class())) {
315  coutE(ObjectHandling) << "RooFactoryWSTool::createArg() ERROR class " << className << " does not inherit from RooAbsArg" << endl;
316  logError();
317  return 0;
318  }
319 
320  _args.clear();
321  string tmp(varList);
322  size_t blevel = 0, end_tok, start_tok = 0;
323  bool litmode = false;
324  for (end_tok = 0; end_tok < tmp.length(); end_tok++) {
325  // Keep track of opening and closing brackets
326  if (tmp[end_tok]=='{' || tmp[end_tok]=='(' || tmp[end_tok]=='[') blevel++;
327  if (tmp[end_tok]=='}' || tmp[end_tok]==')' || tmp[end_tok]==']') blevel--;
328 
329  // Keep track of string literals
330  if (tmp[end_tok]=='"' || tmp[end_tok]=='\'') litmode = !litmode;
331 
332  // If we encounter a comma at zero bracket level
333  // push the current substring from start_tok to end_tok
334  // and start the next token
335  if (litmode == false && blevel == 0 && tmp[end_tok] == ',') {
336  _args.push_back(tmp.substr(start_tok, end_tok - start_tok));
337  start_tok = end_tok+1;
338  }
339  }
340  _args.push_back(tmp.substr(start_tok, end_tok));
341 
342  // Try CINT interface
343  pair<list<string>,unsigned int> ca = ctorArgs(className,_args.size()+2) ;
344  if (ca.first.size()==0) {
345  coutE(ObjectHandling) << "RooFactoryWSTool::createArg() ERROR no suitable constructor found for class " << className << endl ;
346  logError() ;
347  return 0 ;
348  }
349 
350 
351  // Check if number of provided args is in valid range (add two to accomodate name and title strings)
352  if (_args.size()+2<ca.second || _args.size()+2>ca.first.size()) {
353  if (ca.second==ca.first.size()) {
354  coutE(ObjectHandling) << "RooFactoryWSTool::createArg() ERROR number of arguments provided (" << _args.size() << ") for class is invalid, " << className
355  << " expects " << ca.first.size()-2 << endl ;
356  logError() ;
357  } else {
358  coutE(ObjectHandling) << "RooFactoryWSTool::createArg() ERROR number of arguments provided (" << _args.size() << ") for class is invalid " << className
359  << " expect number between " << ca.second-2 << " and " << ca.first.size()-2 << endl ;
360  logError() ;
361  }
362  return 0 ;
363  }
364 
365  // Now construct CINT constructor spec, start with mandatory name and title args
366  string cintExpr(Form("new %s(\"%s\",\"%s\"",className,objName,objName)) ;
367 
368  // Install argument in static data member to be accessed below through static CINT interface functions
369  _of = this ;
370 
371 
372  try {
373  Int_t i(0) ;
374  list<string>::iterator ti = ca.first.begin() ; ++ti ; ++ti ;
375  for (vector<string>::iterator ai = _args.begin() ; ai != _args.end() ; ++ai,++ti,++i) {
376  if ((*ti)=="RooAbsReal&" || (*ti)=="const RooAbsReal&") {
377  RooFactoryWSTool::as_FUNC(i) ;
378  cintExpr += Form(",RooFactoryWSTool::as_FUNC(%d)",i) ;
379  } else if ((*ti)=="RooAbsArg&" || (*ti)=="const RooAbsArg&") {
380  RooFactoryWSTool::as_ARG(i) ;
381  cintExpr += Form(",RooFactoryWSTool::as_ARG(%d)",i) ;
382  } else if ((*ti)=="RooRealVar&" || (*ti)=="const RooRealVar&") {
383  RooFactoryWSTool::as_VAR(i) ;
384  cintExpr += Form(",RooFactoryWSTool::as_VAR(%d)",i) ;
385  } else if ((*ti)=="RooAbsRealLValue&" || (*ti)=="const RooAbsRealLValue&") {
386  RooFactoryWSTool::as_VARLV(i) ;
387  cintExpr += Form(",RooFactoryWSTool::as_VARLV(%d)",i) ;
388  } else if ((*ti)=="RooCategory&" || (*ti)=="const RooCategory&") {
389  RooFactoryWSTool::as_CAT(i) ;
390  cintExpr += Form(",RooFactoryWSTool::as_CAT(%d)",i) ;
391  } else if ((*ti)=="RooAbsCategory&" || (*ti)=="const RooAbsCategory&") {
392  RooFactoryWSTool::as_CATFUNC(i) ;
393  cintExpr += Form(",RooFactoryWSTool::as_CATFUNC(%d)",i) ;
394  } else if ((*ti)=="RooAbsCategoryLValue&" || (*ti)=="const RooAbsCategoryLValue&") {
395  RooFactoryWSTool::as_CATLV(i) ;
396  cintExpr += Form(",RooFactoryWSTool::as_CATLV(%d)",i) ;
397  } else if ((*ti)=="RooAbsPdf&" || (*ti)=="const RooAbsPdf&") {
398  RooFactoryWSTool::as_PDF(i) ;
399  cintExpr += Form(",RooFactoryWSTool::as_PDF(%d)",i) ;
400  } else if ((*ti)=="RooResolutionModel&" || (*ti)=="const RooResolutionModel&") {
401  RooFactoryWSTool::as_RMODEL(i) ;
402  cintExpr += Form(",RooFactoryWSTool::as_RMODEL(%d)",i) ;
403  } else if ((*ti)=="RooAbsData&" || (*ti)=="const RooAbsData&") {
404  RooFactoryWSTool::as_DATA(i) ;
405  cintExpr += Form(",RooFactoryWSTool::as_DATA(%d)",i) ;
406  } else if ((*ti)=="RooDataSet&" || (*ti)=="const RooDataSet&") {
407  RooFactoryWSTool::as_DSET(i) ;
408  cintExpr += Form(",RooFactoryWSTool::as_DSET(%d)",i) ;
409  } else if ((*ti)=="RooDataHist&" || (*ti)=="const RooDataHist&") {
410  RooFactoryWSTool::as_DHIST(i) ;
411  cintExpr += Form(",RooFactoryWSTool::as_DHIST(%d)",i) ;
412  } else if ((*ti)=="const RooArgSet&") {
413  RooFactoryWSTool::as_SET(i) ;
414  cintExpr += Form(",RooFactoryWSTool::as_SET(%d)",i) ;
415  } else if ((*ti)=="const RooArgList&") {
416  RooFactoryWSTool::as_LIST(i) ;
417  cintExpr += Form(",RooFactoryWSTool::as_LIST(%d)",i) ;
418  } else if ((*ti)=="const char*") {
419  RooFactoryWSTool::as_STRING(i) ;
420  cintExpr += Form(",RooFactoryWSTool::as_STRING(%d)",i) ;
421  } else if ((*ti)=="Int_t" || (*ti)=="int" || (*ti)=="Bool_t" || (*ti)=="bool") {
422  RooFactoryWSTool::as_INT(i) ;
423  cintExpr += Form(",RooFactoryWSTool::as_INT(%d)",i) ;
424  } else if ((*ti)=="Double_t") {
425  RooFactoryWSTool::as_DOUBLE(i) ;
426  cintExpr += Form(",RooFactoryWSTool::as_DOUBLE(%d)",i) ;
427  } else if (isEnum(ti->c_str())) {
428 
429  string qualvalue ;
430  if (_args[i].find(Form("%s::",className)) != string::npos) {
431  qualvalue = _args[i].c_str() ;
432  } else {
433  qualvalue = Form("%s::%s",className,_args[i].c_str()) ;
434  }
435  if (isValidEnumValue(ti->c_str(),qualvalue.c_str())) {
436  cintExpr += Form(",(%s)%s",ti->c_str(),qualvalue.c_str()) ;
437  } else {
438  throw string(Form("Supplied argument %s does not represent a valid state of enum %s",_args[i].c_str(),ti->c_str())) ;
439  }
440  } else {
441  // Check if generic object store has argument of given name and type
442  TObject& obj = RooFactoryWSTool::as_OBJ(i) ;
443 
444  // Strip argument type to bare type (i.e. const X& -> X)
445  string btype ;
446  if (ti->find("const ")==0) {
447  btype = ti->c_str()+6 ;
448  } else {
449  btype = *ti ;
450  }
451  if (btype.find("&")) {
452  btype.erase(btype.size()-1,btype.size()) ;
453  }
454 
455  // If btype if a typedef, substitute it by the true type name
456  btype = string(TEnum::GetEnum(btype.c_str())->GetName());
457 
458  if (obj.InheritsFrom(btype.c_str())) {
459  cintExpr += Form(",(%s&)RooFactoryWSTool::as_OBJ(%d)",ti->c_str(),i) ;
460  } else {
461  throw string(Form("Required argument with name %s of type '%s' is not in the workspace",_args[i].c_str(),ti->c_str())) ;
462  }
463  }
464  }
465  cintExpr += ") ;" ;
466  } catch (const string &err) {
467  coutE(ObjectHandling) << "RooFactoryWSTool::createArg() ERROR constructing " << className << "::" << objName << ": " << err << endl ;
468  logError() ;
469  return 0 ;
470  }
471 
472  cxcoutD(ObjectHandling) << "RooFactoryWSTool::createArg() Construct expression is " << cintExpr << endl ;
473 
474  // Call CINT to perform constructor call. Catch any error thrown by argument conversion method
475  RooAbsArg* arg = (RooAbsArg*) gROOT->ProcessLineFast(cintExpr.c_str()) ;
476 
477  if (arg) {
478  if (string(className)=="RooGenericPdf") {
479  arg->setStringAttribute("factory_tag",Form("EXPR::%s(%s)",objName,varList)) ;
480  } else if (string(className)=="RooFormulaVar") {
481  arg->setStringAttribute("factory_tag",Form("expr::%s(%s)",objName,varList)) ;
482  } else {
483  arg->setStringAttribute("factory_tag",Form("%s::%s(%s)",className,objName,varList)) ;
484  }
485  if (_ws->import(*arg,Silence())) logError() ;
486  RooAbsArg* ret = _ws->arg(objName) ;
487  delete arg ;
488  return ret ;
489  } else {
490  coutE(ObjectHandling) << "RooFactoryWSTool::createArg() ERROR in CINT constructor call to create object" << endl ;
491  logError() ;
492  return 0 ;
493  }
494 }
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 
498 RooAddPdf* RooFactoryWSTool::add(const char *objName, const char* specList, Bool_t recursiveCoefs)
499 {
500  // Spec list is of form a*A,b*B,c*C,D [ *d]
501 
502  RooArgList pdfList ;
503  RooArgList coefList ;
504  RooArgList pdfList2 ;
505 
506  try {
507 
508  char buf[BUFFER_SIZE] ;
509  strlcpy(buf,specList,BUFFER_SIZE) ;
510  char* save ;
511  char* tok = R__STRTOK_R(buf,",",&save) ;
512  while(tok) {
513  char* star=strchr(tok,'*') ;
514  if (star) {
515  *star=0 ;
516  pdfList.add(asPDF(star+1)) ;
517  coefList.add(asFUNC(tok)) ;
518  } else {
519  pdfList2.add(asPDF(tok)) ;
520  }
521  tok = R__STRTOK_R(0,",",&save) ;
522  }
523  pdfList.add(pdfList2) ;
524 
525  } catch (const string &err) {
526  coutE(ObjectHandling) << "RooFactoryWSTool::add(" << objName << ") ERROR creating RooAddPdf: " << err << endl ;
527  logError() ;
528  return 0 ;
529  }
530 
531  RooAddPdf* pdf = new RooAddPdf(objName,objName,pdfList,coefList,recursiveCoefs) ;
532  pdf->setStringAttribute("factory_tag",Form("SUM::%s(%s)",objName,specList)) ;
533  if (_ws->import(*pdf,Silence())) logError() ;
534  return (RooAddPdf*) _ws->pdf(objName) ;
535 }
536 
537 
538 ////////////////////////////////////////////////////////////////////////////////
539 
540 RooRealSumPdf* RooFactoryWSTool::amplAdd(const char *objName, const char* specList)
541 {
542  // Spec list is of form a*A,b*B,c*C,D [ *d]
543 
544  RooArgList amplList ;
545  RooArgList coefList ;
546  RooArgList amplList2 ;
547 
548  try {
549 
550  char buf[BUFFER_SIZE] ;
551  strlcpy(buf,specList,BUFFER_SIZE) ;
552  char* save ;
553  char* tok = R__STRTOK_R(buf,",",&save) ;
554  while(tok) {
555  char* star=strchr(tok,'*') ;
556  if (star) {
557  *star=0 ;
558  amplList.add(asFUNC(star+1)) ;
559  coefList.add(asFUNC(tok)) ;
560  } else {
561  amplList2.add(asFUNC(tok)) ;
562  }
563  tok = R__STRTOK_R(0,",",&save) ;
564  }
565  amplList.add(amplList2) ;
566 
567  } catch (const string &err) {
568  coutE(ObjectHandling) << "RooFactoryWSTool::add(" << objName << ") ERROR creating RooRealSumPdf: " << err << endl ;
569  logError() ;
570  return 0 ;
571  }
572 
573  RooRealSumPdf* pdf = new RooRealSumPdf(objName,objName,amplList,coefList,(amplList.getSize()==coefList.getSize())) ;
574  pdf->setStringAttribute("factory_tag",Form("ASUM::%s(%s)",objName,specList)) ;
575  if (_ws->import(*pdf,Silence())) logError() ;
576  return (RooRealSumPdf*) _ws->pdf(objName) ;
577 }
578 
579 
580 ////////////////////////////////////////////////////////////////////////////////
581 
582 RooProdPdf* RooFactoryWSTool::prod(const char *objName, const char* pdfList)
583 {
584  _of = this ;
585 
586  // Separate conditional and non-conditional p.d.f terms
587  RooLinkedList cmdList ;
588  string regPdfList="{" ;
589  char buf[BUFFER_SIZE] ;
590  strlcpy(buf,pdfList,BUFFER_SIZE) ;
591  char* save ;
592  char* tok = R__STRTOK_R(buf,",",&save) ;
593  while(tok) {
594  char *sep = strchr(tok,'|') ;
595  if (sep) {
596  // Conditional term
597  *sep=0 ;
598  sep++ ;
599 
600  // |x is conditional on x, |~x is conditional on all but x
601  Bool_t invCond(kFALSE) ;
602  if (*sep=='~') {
603  invCond=kTRUE ;
604  sep++ ;
605  }
606 
607  try {
608  cmdList.Add(Conditional(asSET(tok),asSET(sep),!invCond).Clone()) ;
609  } catch (const string &err) {
610  coutE(ObjectHandling) << "RooFactoryWSTool::prod(" << objName << ") ERROR creating RooProdPdf Conditional argument: " << err << endl ;
611  logError() ;
612  return 0 ;
613  }
614 
615  } else {
616  // Regular term
617  if (regPdfList.size()>1) {
618  regPdfList += "," ;
619  }
620  regPdfList += tok ;
621  }
622  tok = R__STRTOK_R(0,",",&save) ;
623  }
624  regPdfList += "}" ;
625 
626  RooProdPdf* pdf = 0 ;
627  try {
628  pdf = new RooProdPdf(objName,objName,asSET(regPdfList.c_str()),cmdList) ;
629  } catch (const string &err) {
630  coutE(ObjectHandling) << "RooFactoryWSTool::prod(" << objName << ") ERROR creating RooProdPdf input set of regular p.d.f.s: " << err << endl ;
631  logError() ;
632  pdf = 0 ;
633  }
634  cmdList.Delete() ;
635 
636  if (pdf) {
637  pdf->setStringAttribute("factory_tag",Form("PROD::%s(%s)",objName,pdfList)) ;
638  if (_ws->import(*pdf,Silence())) logError() ;
639  delete pdf ;
640  return (RooProdPdf*) _ws->pdf(objName) ;
641  } else {
642  return 0 ;
643  }
644 }
645 
646 
647 
648 ////////////////////////////////////////////////////////////////////////////////
649 
650 RooSimultaneous* RooFactoryWSTool::simul(const char* objName, const char* indexCat, const char* pdfMap)
651 {
652  map<string,RooAbsPdf*> theMap ;
653  // Add p.d.f. to index state mappings
654  char buf[BUFFER_SIZE] ;
655  strlcpy(buf,pdfMap,BUFFER_SIZE) ;
656  char* save ;
657  char* tok = R__STRTOK_R(buf,",",&save) ;
658  while(tok) {
659  char* eq = strchr(tok,'=') ;
660  if (!eq) {
661  coutE(ObjectHandling) << "RooFactoryWSTool::simul(" << objName << ") ERROR creating RooSimultaneous::" << objName
662  << " expect mapping token of form 'state=pdfName', but found '" << tok << "'" << endl ;
663  logError() ;
664  return 0 ;
665  } else {
666  *eq = 0 ;
667 
668  try {
669  theMap[tok] = &asPDF(eq+1) ;
670  } catch (const string &err ) {
671  coutE(ObjectHandling) << "RooFactoryWSTool::simul(" << objName << ") ERROR creating RooSimultaneous: " << err << endl ;
672  logError() ;
673  }
674  }
675  tok = R__STRTOK_R(0,",",&save) ;
676  }
677 
678 
679  // Create simultaneous p.d.f.
680  RooSimultaneous* pdf(0) ;
681  try {
682  pdf = new RooSimultaneous(objName,objName,theMap,asCATLV(indexCat)) ;
683  } catch (const string &err) {
684  coutE(ObjectHandling) << "RooFactoryWSTool::simul(" << objName << ") ERROR creating RooSimultaneous::" << objName << " " << err << endl ;
685  logError() ;
686  }
687 
688  // Import p.d.f into workspace
689  pdf->setStringAttribute("factory_tag",Form("SIMUL::%s(%s,%s)",objName,indexCat,pdfMap)) ;
690  if (_ws->import(*pdf,Silence())) logError() ;
691  return (RooSimultaneous*) _ws->pdf(objName) ;
692 }
693 
694 
695 
696 
697 ////////////////////////////////////////////////////////////////////////////////
698 
699 RooAddition* RooFactoryWSTool::addfunc(const char *objName, const char* specList)
700 {
701  RooArgList sumlist1 ;
702  RooArgList sumlist2 ;
703 
704  try {
705 
706  char buf[BUFFER_SIZE] ;
707  strlcpy(buf,specList,BUFFER_SIZE) ;
708  char* save ;
709  char* tok = R__STRTOK_R(buf,",",&save) ;
710  while(tok) {
711  char* star=strchr(tok,'*') ;
712  if (star) {
713  *star=0 ;
714  sumlist2.add(asFUNC(star+1)) ;
715  sumlist1.add(asFUNC(tok)) ;
716  } else {
717  sumlist1.add(asFUNC(tok)) ;
718  }
719  tok = R__STRTOK_R(0,",",&save) ;
720  }
721 
722  } catch (const string &err) {
723  coutE(ObjectHandling) << "RooFactoryWSTool::addfunc(" << objName << ") ERROR creating RooAddition: " << err << endl ;
724  logError() ;
725  return 0 ;
726  }
727 
728  if (sumlist2.getSize()>0 && (sumlist1.getSize()!=sumlist2.getSize())) {
729  coutE(ObjectHandling) << "RooFactoryWSTool::addfunc(" << objName << ") ERROR creating RooAddition: syntax error: either all sum terms must be products or none" << endl ;
730  logError() ;
731  return 0 ;
732  }
733 
734 
735  RooAddition* sum ;
736  if (sumlist2.getSize()>0) {
737  sum = new RooAddition(objName,objName,sumlist1,sumlist2) ;
738  } else {
739  sum = new RooAddition(objName,objName,sumlist1) ;
740  }
741 
742  sum->setStringAttribute("factory_tag",Form("sum::%s(%s)",objName,specList)) ;
743  if (_ws->import(*sum,Silence())) logError() ;
744  delete sum ;
745  return (RooAddition*) _ws->pdf(objName) ;
746 
747 }
748 
749 
750 
751 
752 ////////////////////////////////////////////////////////////////////////////////
753 
754 RooProduct* RooFactoryWSTool::prodfunc(const char *objName, const char* pdfList)
755 {
756  return (RooProduct*) createArg("RooProduct",objName,Form("{%s}",pdfList)) ;
757 }
758 
759 
760 
761 
762 
763 ////////////////////////////////////////////////////////////////////////////////
764 /// Process high-level object creation syntax
765 /// Accepted forms of syntax are
766 ///
767 ///
768 /// Creating variables
769 ///
770 /// x[-10,10] - Create variable x with given range and put it in workspace
771 /// x[3,-10,10] - Create variable x with given range and initial value and put it in workspace
772 /// x[3] - Create variable x with given constant value
773 ///
774 /// <numeric literal> - Numeric literal expressions (0.5, -3 etc..) are converted to a RooConst(<numeric literal>)
775 /// where ever a RooAbsReal or RooAbsArg argument is expected
776 ///
777 /// Creating categories
778 ///
779 /// c[lep,kao,nt1,nt2] - Create category c with given state names
780 /// tag[B0=1,B0bar=-1] - Create category tag with given state names and index assignments
781 ///
782 ///
783 /// Creating functions and p.d.f.s
784 ///
785 /// MyPdf::g(x,m,s) - Create p.d.f or function of type MyPdf with name g with argument x,m,s
786 /// Interpretation and number of arguments are mapped to the constructor arguments of the class
787 /// (after the name and title).
788 ///
789 /// MyPdf(x,m,s) - As above, but with an implicitly defined (unique) object name
790 ///
791 ///
792 /// Creating sets and lists (to be used as inputs above)
793 ///
794 /// {a,b,c} - Create RooArgSet or RooArgList (as determined by context) from given contents
795 ///
796 ///
797 ///
798 /// Objects that are not created, are assumed to exist in the workspace
799 /// Object creation expressions as shown above can be nested, e.g. one can do
800 ///
801 /// RooGaussian::g(x[-10,10],m[0],3)
802 ///
803 /// to create a p.d.f and its variables in one go. This nesting can be applied recursively e.g.
804 ///
805 /// SUM::model( f[0.5,0,1] * RooGaussian::g( x[-10,10], m[0], 3] ),
806 /// RooChebychev::c( x, {a0[0.1],a1[0.2],a2[-0.3]} ))
807 ///
808 /// creates the sum of a Gaussian and a Chebychev and all its variables
809 ///
810 ///
811 /// A seperate series of operator meta-type exists to simplify the construction of composite expressions
812 /// meta-types in all capitals (SUM) create p.d.f.s, meta types in lower case (sum) create
813 /// functions.
814 ///
815 ///
816 /// SUM::name(f1*pdf1,f2*pdf2,pdf3] -- Create sum p.d.f name with value f1*pdf1+f2*pdf2+(1-f1-f2)*pdf3
817 /// RSUM::name(f1*pdf1,f2*pdf2,pdf3] -- Create recursive sum p.d.f. name with value f1*pdf1 + (1-f1)(f2*pdf2 + (1-f2)pdf3)
818 /// ASUM::name(f1*amp1,f2*amp2,amp3] -- Create sum p.d.f. name with value f1*amp1+f2*amp2+(1-f1-f2)*amp3 where amplX are amplitudes of type RooAbsReal
819 /// sum::name(a1,a2,a3] -- Create sum function with value a1+a2+a3
820 /// sum::name(a1*b1,a2*b2,a3*b 3] -- Create sum function with value a1*b1+a2*b2+a3*b3
821 ///
822 /// PROD::name(pdf1,pdf2] -- Create product of p.d.f with 'name' with given input p.d.fs
823 /// PROD::name(pdf1|x,pdf2] -- Create product of conditional p.d.f. pdf1 given x and pdf2
824 /// prod::name(a,b,c] -- Create production function with value a*b*c
825 ///
826 /// SIMUL::name(cat,a=pdf1,b=pdf2] -- Create simultaneous p.d.f index category cat. Make pdf1 to state a, pdf2 to state b
827 ///
828 /// EXPR::name('expr',var,...] -- Create an generic p.d.f that interprets the given expression
829 /// expr::name('expr',var,...] -- Create an generic function that interprets the given expression
830 ///
831 ///
832 /// The functionality of high level object creation tools like RooSimWSTool, RooCustomizer and RooClassFactory
833 /// is also interfaced through meta-types in the factory
834 ///
835 ///
836 /// Interface to RooSimWSTool
837 ///
838 /// SIMCLONE::name( modelPdf, $ParamSplit(...),
839 /// $ParamSplitConstrained(...), $Restrict(...) ] -- Clone-and-customize modelPdf according to ParamSplit and ParamSplitConstrained()
840 /// specifications and return a RooSimultaneous p.d.f. of all built clones
841 ///
842 /// MSIMCLONE::name( masterIndex,
843 /// $AddPdf(mstate1, modelPdf1, $ParamSplit(...)),
844 /// $AddPdf(mstate2,modelPdf2),...) ] -- Clone-and-customize multiple models (modelPdf1,modelPdf2) according to ParamSplit and
845 /// ParamSplitConstrained() specifications and return a RooSimultaneous p.d.f. of all built clones,
846 /// using the specified master index to map prototype p.d.f.s to master states
847 /// Interface to RooCustomizer
848 ///
849 /// EDIT::name( orig, substNode=origNode), ... ] -- Create a clone of input object orig, with the specified replacements operations executed
850 /// EDIT::name( orig, origNode=$REMOVE(), ... ] -- Create clone of input removing term origNode from all PROD() terms that contained it
851 /// EDIT::name( orig, origNode=$REMOVE(prodname,...), ... ] -- As above, but restrict removal of origNode to PROD term(s) prodname,...
852 ///
853 ///
854 /// Interface to RooClassFactory
855 ///
856 /// CEXPR::name('expr',var,...] -- Create an custom compiled p.d.f that evaluates the given expression
857 /// cexpr::name('expr',var,...] -- Create an custom compiled function that evaluates the given expression
858 ///
859 ///
860 /// $MetaType(...) - Meta argument that does not result in construction of an object but is used logically organize
861 /// input arguments in certain operator p.d.f. constructions. The defined meta arguments are context dependent.
862 ///
863 /// The only meta argument that is defined globally is $Alias(typeName,aliasName) to
864 /// define aliases for type names. For the definition of meta arguments in operator p.d.f.s
865 /// see the definitions below
866 
867 RooAbsArg* RooFactoryWSTool::process(const char* expr)
868 {
869 
870 // cout << "RooFactoryWSTool::process() " << expr << endl ;
871 
872  // First perform basic syntax check
873  if (checkSyntax(expr)) {
874  return 0 ;
875  }
876 
877  // Allocate work buffer
878  char* buf = new char[strlen(expr)+1] ;
879 
880  // Copy to buffer while absorbing white space and newlines
881  char* buftmp = buf ;
882  while(*expr) {
883  if (!isspace(*expr)) {
884  *buftmp = *expr ;
885  buftmp++ ;
886  }
887  expr++ ;
888  }
889  *buftmp=0 ;
890 
891 
892  // Clear error count and start a transaction in the workspace
893  clearError() ;
894  ws().startTransaction() ;
895 
896  // Process buffer
897  string out ;
898  try {
899  out = processExpression(buf) ;
900  } catch (const string &error) {
901  coutE(ObjectHandling) << "RooFactoryWSTool::processExpression() ERROR in parsing: " << error << endl ;
902  logError() ;
903  }
904 
905  // If there were no errors commit the transaction, cancel it otherwise
906  if (errorCount()>0) {
907  coutE(ObjectHandling) << "RooFactoryWSTool::processExpression() ERRORS detected, transaction to workspace aborted, no objects committed" << endl ;
908  ws().cancelTransaction() ;
909  } else {
910  ws().commitTransaction() ;
911  }
912 
913 
914  // Delete buffer
915  delete[] buf ;
916 
917  return out.size() ? ws().arg(out.c_str()) : 0 ;
918 }
919 
920 
921 
922 
923 ////////////////////////////////////////////////////////////////////////////////
924 /// Process a single high-level expression or list of
925 /// expressions. The returned string a the reduced expression where
926 /// all inline object creations have been executed and substituted
927 /// with the name of the created object
928 ///
929 /// e.g. 'RooGaussian::g(x,m,s)' --> 'g'
930 /// '{x(-10,10),s} --> '{x,s}'
931 
932 std::string RooFactoryWSTool::processExpression(const char* token)
933 {
934  // Delegate handling to list processor if token starts with {, otherwise
935  // call single expression processor
936  if (string(token).find("$Alias(")==0) {
937  processAliasExpression(token) ;
938  }
939 
940  if (token[0]=='{') {
941  // Process token as list if it starts with '{'
942  return processListExpression(token) ;
943  } else {
944  // Process token as single item otherwise
945  return processCompositeExpression(token) ;
946  }
947 }
948 
949 
950 
951 ////////////////////////////////////////////////////////////////////////////////
952 /// Process a single composite expression
953 ///
954 /// e.g. 'A=RooGaussian::g[x,m,s]' --> 'A=g'
955 /// e.g. 'f[0,1]*RooGaussian::g[x,m,s]' --> 'f*g'
956 /// e.g. 'RooGaussian::g(x,y,s)|x' --> g|x'
957 /// e.g. '$MetaArg(RooGaussian::g[x,m,s],blah)' --> '$MetaArg(g,blah)'
958 
959 std::string RooFactoryWSTool::processCompositeExpression(const char* token)
960 {
961  // Allocate and fill work buffer
962  const size_t bufBaseSize = strlen(token)+1;
963  char* buf_base = new char[bufBaseSize] ;
964  char* buf = buf_base ;
965  strlcpy(buf,token,bufBaseSize) ;
966  char* p = buf ;
967 
968  list<string> singleExpr ;
969  list<char> separator ;
970  Int_t blevel(0) ;
971  Bool_t litmode(kFALSE) ;
972  while(*p) {
973 
974  // Keep track of opening and closing brackets
975  if (*p=='{' || *p=='(' || *p=='[') blevel++ ;
976  if (*p=='}' || *p==')' || *p==']') blevel-- ;
977 
978  // Keep track of string literals
979  if (*p=='"' || *p=='\'') litmode = !litmode ;
980 
981  // If we are zero-bracket level and encounter a |, store
982  // the remainder of the string as suffix and exit loop
983  if (!litmode && blevel==0 && ( (*p)=='=' || (*p) == '|' || (*p) == '*')) {
984  separator.push_back(*p) ;
985  *p=0 ;
986  singleExpr.push_back(buf) ;
987  buf = p+1 ;
988  }
989  p++ ;
990  }
991  if (*buf) {
992  singleExpr.push_back(buf) ;
993  }
994  if (singleExpr.size()==1) {
995  string ret = processSingleExpression(token) ;
996  delete[] buf_base ;
997  return ret ;
998  }
999 
1000  string ret ;
1001  list<char>::iterator ic = separator.begin() ;
1002  for (list<string>::iterator ii = singleExpr.begin() ; ii!=singleExpr.end() ; ++ii) {
1003  ret += processSingleExpression(ii->c_str()) ;
1004  if (ic != separator.end()) {
1005  ret += *ic ;
1006  ++ic ;
1007  }
1008  }
1009 
1010  delete[] buf_base ;
1011  return ret ;
1012 }
1013 
1014 
1015 
1016 ////////////////////////////////////////////////////////////////////////////////
1017 /// Process a single high-level expression. The returned string a the reduced
1018 /// expression where all inline object creations have been executed and substituted
1019 /// with the name of the created object
1020 ///
1021 /// e.g. 'RooGaussian::g(x,m,s)' --> 'g'
1022 /// e.g. 'x[-10,10]' --> 'x'
1023 
1024 std::string RooFactoryWSTool::processSingleExpression(const char* arg)
1025 {
1026  // Handle empty strings here
1027  if (strlen(arg)==0) {
1028  return string("") ;
1029  }
1030 
1031  // Handle string literal case
1032  if (arg[0]=='\'' || arg[0]=='"') {
1033  return string(arg) ;
1034  }
1035 
1036  // Allocate and fill work buffer
1037  const size_t bufSize = strlen(arg)+1;
1038  char* buf = new char[bufSize] ;
1039  strlcpy(buf,arg,bufSize) ;
1040  char* bufptr = buf ;
1041 
1042  string func,prefix ;
1043  vector<string> args ;
1044 
1045  // Process token into arguments
1046  char* save ;
1047  char* tmpx = R__STRTOK_R(buf,"([",&save) ;
1048  func = tmpx ? tmpx : "" ;
1049  char* p = R__STRTOK_R(0,"",&save) ;
1050 
1051  // Return here if token is fundamental
1052  if (!p) {
1053  delete[] buf ;
1054  return arg ;
1055  }
1056 
1057 
1058  char* tok = p ;
1059  Int_t blevel=0 ;
1060  Bool_t litmode(kFALSE) ;
1061  while(*p) {
1062 
1063  // Keep track of opening and closing brackets
1064  if (*p=='{' || *p=='(' || *p=='[') blevel++ ;
1065  if (*p=='}' || *p==')' || *p==']') blevel-- ;
1066 
1067  // Keep track of string literals
1068  if (*p=='"' || *p=='\'') litmode = !litmode ;
1069 
1070 
1071  // If we encounter a comma at zero bracket level
1072  // finalize the current token as a completed argument
1073  // and start the next token
1074  if (!litmode && blevel==0 && ((*p)==',')) {
1075  *p = 0 ;
1076  args.push_back(tok) ;
1077  tok = p+1 ;
1078  }
1079 
1080  p++ ;
1081  }
1082 
1083  // If the last character was a closing bracket, kill
1084  // it in the buffer
1085  if (p>bufptr && (*(p-1)==')'||*(p-1)==']')) {
1086  *(p-1)=0 ;
1087  }
1088 
1089  // Finalize last token as argument
1090  string tmp = tok ;
1091 
1092  // If there is a suffix left in the work buffer attach it to
1093  // this argument
1094  p = R__STRTOK_R(0,"",&save) ;
1095  if (p) tmp += p ;
1096  args.push_back(tmp) ;
1097 
1098  // Delete the work buffer
1099  delete[] buf ;
1100 
1101  // If function contains :: then call createArg to process this arg, otherwise
1102  // call createVariable
1103  string ret ;
1104 
1105  // Determine type of leading bracket
1106  char lb = ' ' ;
1107  for(const char* pp=arg ; *pp!=0 ; pp++) {
1108  if (*pp=='(' || *pp=='[' || *pp=='{') {
1109  lb = *pp ;
1110  break ;
1111  }
1112  }
1113 
1114  if (strstr(func.c_str(),"::")) {
1115  if (lb=='(') {
1116  // Create function argument with instance name
1117  ret= processCreateArg(func,args) ;
1118  } else {
1119  coutE(ObjectHandling) << "RooFactoryWSTool::processSingleExpression(" << arg << "): ERROR: Syntax error: Class::Instance must be followed by (...)" << endl ;
1120  logError() ;
1121  }
1122  } else if (func[0]!='$'){
1123  if (lb=='[') {
1124  // Create variable argument
1125  ret= processCreateVar(func,args) ;
1126  } else if (lb=='(') {
1127 
1128  // Create function argument with autoname
1129  string autoname ;
1130  if (!_autoNamePrefix.empty()) {
1131  // If we're inside a function creation call to a higher level object, use its
1132  // name as base for the autoname
1133  autoname = (Form("%s::%s",func.c_str(),_autoNamePrefix.top().c_str())) ;
1134  } else {
1135  // Otherwise find a free global_%d name
1136  static Int_t globCounter = 0 ;
1137  while(true) {
1138  autoname = Form("gobj%d",globCounter) ;
1139  globCounter++ ;
1140  if (!ws().arg(autoname.c_str())) {
1141  break ;
1142  }
1143  }
1144  autoname = Form("%s::%s",func.c_str(),autoname.c_str()) ;
1145  }
1146  ret= processCreateArg(autoname,args) ;
1147  } else {
1148  coutE(ObjectHandling) << "RooFactoryWSTool::processSingleExpression(" << arg << "): ERROR: Syntax error: expect either Class(...) or Instance[...]" << endl ;
1149  logError() ;
1150  }
1151  } else {
1152  if (lb=='(') {
1153  // Process meta function (compile arguments, but not meta-function itself)
1154  ret= processMetaArg(func,args) ;
1155  } else {
1156  coutE(ObjectHandling) << "RooFactoryWSTool::processSingleExpression(" << arg << "): ERROR: Syntax error: $MetaClass must be followed by (...)" << endl ;
1157  logError() ;
1158  }
1159  }
1160 
1161  // Return reduced token with suffix
1162  return ret ;
1163 }
1164 
1165 
1166 ////////////////////////////////////////////////////////////////////////////////
1167 /// Process a list of high-level expression. The returned string a the reduced
1168 /// expression list where all inline object creations have been executed and substituted
1169 /// with the name of the created object
1170 ///
1171 /// E.g. '{x(-10,10),s} --> '{x,s}'
1172 
1173 string RooFactoryWSTool::processListExpression(const char* arg)
1174 {
1175  // Allocate and fill work buffer
1176  const size_t bufSize = strlen(arg)+1;
1177  char* buf = new char[bufSize] ;
1178  strlcpy(buf,arg,bufSize) ;
1179 
1180  vector<string> args ;
1181 
1182  // Start running pointer at position 1 to skip opening bracket
1183  char* tok = buf+1 ;
1184  char* p = buf+1 ;
1185 
1186  // Processing look
1187  Int_t level(0) ;
1188  while(*p) {
1189 
1190  // Track bracketing level
1191  if (*p=='{' || *p=='(' || *p=='[') level++ ;
1192  if (*p=='}' || *p==')' || *p==']') level-- ;
1193 
1194 
1195  // If we encounter a comma at zero bracket level
1196  // finalize the current token as a completed argument
1197  // and start the next token
1198  if (level==0 && ((*p)==',')) {
1199  *p = 0 ;
1200  args.push_back(tok) ;
1201  tok = p+1 ;
1202  }
1203 
1204  p++ ;
1205  }
1206 
1207  // Finalize token as last argument
1208  if (p>buf && *(p-1)=='}') {
1209  *(p-1)=0 ;
1210  }
1211  args.push_back(tok) ;
1212 
1213  // Delete work buffer
1214  delete[] buf ;
1215 
1216  // Process each argument in list and construct reduced
1217  // expression to be returned
1218  string ret("{") ;
1219  vector<string>::iterator iter = args.begin() ;
1220  Int_t i(0) ;
1221  while(iter!= args.end()) {
1222  if (strlen(ret.c_str())>1) ret += "," ;
1223  if (!_autoNamePrefix.empty()) {
1224  _autoNamePrefix.push(Form("%s%d",_autoNamePrefix.top().c_str(),i+1)) ;
1225  }
1226  ret += processSingleExpression(iter->c_str()) ;
1227  if (!_autoNamePrefix.empty()) {
1228  _autoNamePrefix.pop() ;
1229  }
1230  ++iter ;
1231  i++ ;
1232  }
1233  ret += "}" ;
1234 
1235  return ret ;
1236 }
1237 
1238 
1239 
1240 ////////////////////////////////////////////////////////////////////////////////
1241 /// Parse token
1242 
1243 string RooFactoryWSTool::processAliasExpression(const char* token)
1244 {
1245  vector<string> args = splitFunctionArgs(token) ;
1246  if (args.size()!=2) {
1247  coutE(ObjectHandling) << "RooFactorWSTool::processAliasExpression() ERROR $Alias() takes exactly two arguments, " << args.size() << " args found" << endl ;
1248  logError() ;
1249  return string() ;
1250  }
1251 
1252  // Insert alias in table
1253  _typeAliases[args[1]] = args[0] ;
1254 
1255  return string() ;
1256 }
1257 
1258 
1259 
1260 
1261 ////////////////////////////////////////////////////////////////////////////////
1262 
1263 TClass* RooFactoryWSTool::resolveClassName(const char* className)
1264 {
1265  // First do recursive alias expansion
1266  while (true) {
1267  map<string,string>::iterator item = _typeAliases.find(className) ;
1268 
1269  // If an alias is found, recurse
1270  if (item != _typeAliases.end()) {
1271  className = item->second.c_str() ;
1272  } else {
1273  break ;
1274  }
1275  }
1276 
1277  // Now find dealiased class in ROOT class table
1278  TClass* tc = TClass::GetClass(className,kTRUE,kTRUE) ;
1279 
1280  // If its not there, try prefixing with Roo
1281  if (!tc) {
1282  tc = TClass::GetClass(Form("Roo%s",className)) ;
1283  if (!tc) {
1284  coutE(ObjectHandling) << "RooFactoryWSTool::createArg() ERROR class " << className << " not defined in ROOT class table" << endl ;
1285  logError() ;
1286  return 0 ;
1287  }
1288  }
1289  return tc ;
1290 }
1291 
1292 
1293 
1294 ////////////////////////////////////////////////////////////////////////////////
1295 
1296 string RooFactoryWSTool::varTag(string& func, vector<string>& args)
1297 {
1298  string ret ;
1299  ret += func ;
1300  ret += "[" ;
1301  for (vector<string>::iterator iter = args.begin() ; iter!=args.end() ; ++iter) {
1302  if (iter!=args.begin()) {
1303  ret += "," ;
1304  }
1305  ret += *iter ;
1306  }
1307  ret += "]" ;
1308  return ret ;
1309 }
1310 
1311 
1312 
1313 
1314 ////////////////////////////////////////////////////////////////////////////////
1315 /// Glue function between high-level syntax and low-level factory call to createVariable:
1316 /// Process a parsed call to create a variable named 'func'
1317 ///
1318 /// If initial token is non-numeric, a RooCategory will be created, and the args are interpreted
1319 /// as either state names or 'name=id' assignments. Otherwise a RooRealvar is created and the
1320 /// arg list is interpreted as follows:
1321 /// If list has two args, these are interpreted as xmin,xmax
1322 /// If list has three args, these are interpreted as xinit,xmin,xmax
1323 /// If list has one arg, this is interpreted as xinit and the variable is set as constant
1324 
1325 string RooFactoryWSTool::processCreateVar(string& func, vector<string>& args)
1326 {
1327 
1328  // Determine if first arg is numeric
1329  string first = *(args.begin()) ;
1330  if (isdigit(first[0]) || first[0]=='.' || first[0]=='+' || first[0]=='-') {
1331 
1332  // Create a RooRealVar
1333  vector<string>::iterator ai = args.begin() ;
1334  if (args.size()==1) {
1335 
1336  // One argument, create constant variable with given value
1337  Double_t xinit = atof((ai)->c_str()) ;
1338  cxcoutD(ObjectHandling) << "CREATE variable " << func << " xinit = " << xinit << endl ;
1339  RooRealVar tmp(func.c_str(),func.c_str(),xinit) ;
1340  tmp.setStringAttribute("factory_tag",varTag(func,args).c_str()) ;
1341  if (_ws->import(tmp,Silence())) {
1342  logError() ;
1343  }
1344 
1345  } else if (args.size()==2) {
1346 
1347  // Two arguments, create variable with given range
1348  Double_t xlo = atof((ai++)->c_str()) ;
1349  Double_t xhi = atof(ai->c_str()) ;
1350  cxcoutD(ObjectHandling) << "CREATE variable " << func << " xlo = " << xlo << " xhi = " << xhi << endl ;
1351  RooRealVar tmp(func.c_str(),func.c_str(),xlo,xhi) ;
1352  tmp.setStringAttribute("factory_tag",varTag(func,args).c_str()) ;
1353  if (_ws->import(tmp,Silence())) {
1354  logError() ;
1355  }
1356 
1357  } else if (args.size()==3) {
1358 
1359  // Three arguments, create variable with given initial value and range
1360  Double_t xinit = atof((ai++)->c_str()) ;
1361  Double_t xlo = atof((ai++)->c_str()) ;
1362  Double_t xhi = atof(ai->c_str()) ;
1363  cxcoutD(ObjectHandling) << "CREATE variable " << func << " xinit = " << xinit << " xlo = " << xlo << " xhi = " << xhi << endl ;
1364  RooRealVar tmp(func.c_str(),func.c_str(),xinit,xlo,xhi) ;
1365  tmp.setStringAttribute("factory_tag",varTag(func,args).c_str()) ;
1366  if (_ws->import(tmp,Silence())) {
1367  logError() ;
1368  }
1369  }
1370  } else {
1371 
1372  // Create a RooAbsCategory
1373  string allStates ;
1374  for (vector<string>::iterator ai = args.begin() ; ai!=args.end() ; ++ai) {
1375  if (allStates.size()>0) {
1376  allStates += "," ;
1377  }
1378  allStates += *ai ;
1379  }
1380  createCategory(func.c_str(),allStates.c_str()) ;
1381 
1382  }
1383  return func ;
1384 }
1385 
1386 
1387 ////////////////////////////////////////////////////////////////////////////////
1388 /// Glue function between high-level syntax and low-level factory call to createArg:
1389 /// Process a parsed call to create a p.d.f named func
1390 ///
1391 /// The func arg is interpreted as ClassName::ObjectName and the arglist is passed
1392 /// verbatim to createArg. The received arglist is expected to be fully reduced (i.e.
1393 /// all inline object creations must have been compiled)
1394 
1395 string RooFactoryWSTool::processCreateArg(string& func, vector<string>& args)
1396 {
1397  // Allocate and fill work buffer
1398  char buf[BUFFER_SIZE] ;
1399  strlcpy(buf,func.c_str(),BUFFER_SIZE) ;
1400 
1401  // Split function part in class name and instance name
1402  char* save ;
1403  const char *className = R__STRTOK_R(buf,":",&save) ;
1404  const char *instName = R__STRTOK_R(0,":",&save) ;
1405  if (!className) className = "";
1406  if (!instName) instName = "" ;
1407 
1408  // Concatenate list of args into comma separated string
1409  char pargs[BUFFER_SIZE] ;
1410  pargs[0] = 0 ;
1411  vector<string>::iterator iter = args.begin() ;
1412  vector<string> pargv ;
1413  Int_t iarg(0) ;
1414  while(iter!=args.end()) {
1415  if (strlen(pargs)>0) strlcat(pargs,",",BUFFER_SIZE) ;
1416  _autoNamePrefix.push(Form("%s_%d",instName,iarg+1)) ;
1417  string tmp = processExpression(iter->c_str()) ;
1418  _autoNamePrefix.pop() ;
1419  strlcat(pargs,tmp.c_str(),BUFFER_SIZE) ;
1420  pargv.push_back(tmp) ;
1421  ++iter ;
1422  iarg++ ;
1423  }
1424 
1425  // Look up if func is a special
1426  for (map<string,IFace*>::iterator ii=hooks().begin() ; ii!=hooks().end() ; ++ii) {
1427  }
1428  if (hooks().find(className) != hooks().end()) {
1429  IFace* iface = hooks()[className] ;
1430  return iface->create(*this, className,instName,pargv) ;
1431  }
1432 
1433  createArg(className,instName,pargs) ;
1434 
1435  return string(instName) ;
1436 }
1437 
1438 
1439 
1440 ////////////////////////////////////////////////////////////////////////////////
1441 /// Concatenate list of args into comma separated string
1442 
1443 std::string RooFactoryWSTool::processMetaArg(std::string& func, std::vector<std::string>& args)
1444 {
1445  char pargs[BUFFER_SIZE] ;
1446  pargs[0] = 0 ;
1447  vector<string>::iterator iter = args.begin() ;
1448  vector<string> pargv ;
1449  while(iter!=args.end()) {
1450  if (strlen(pargs)>0) strlcat(pargs,",",BUFFER_SIZE) ;
1451  string tmp = processExpression(iter->c_str()) ;
1452  strlcat(pargs,tmp.c_str(),BUFFER_SIZE) ;
1453  pargv.push_back(tmp) ;
1454  ++iter ;
1455  }
1456 
1457  string ret = func+"("+pargs+")" ;
1458  return ret ;
1459 }
1460 
1461 
1462 
1463 
1464 ////////////////////////////////////////////////////////////////////////////////
1465 /// Allocate and fill work buffer
1466 
1467 vector<string> RooFactoryWSTool::splitFunctionArgs(const char* funcExpr)
1468 {
1469  const size_t bufSize = strlen(funcExpr)+1;
1470  char* buf = new char[bufSize] ;
1471  strlcpy(buf,funcExpr,bufSize) ;
1472  char* bufptr = buf ;
1473 
1474  string func ;
1475  vector<string> args ;
1476 
1477  // Process token into arguments
1478  char* save ;
1479  char* tmpx = R__STRTOK_R(buf,"(",&save) ;
1480  func = tmpx ? tmpx : "" ;
1481  char* p = R__STRTOK_R(0,"",&save) ;
1482 
1483  // Return here if token is fundamental
1484  if (!p) {
1485  delete[] buf ;
1486  return args ;
1487  }
1488 
1489  char* tok = p ;
1490  Int_t blevel=0 ;
1491  Bool_t litmode(kFALSE) ;
1492  while(*p) {
1493 
1494  // Keep track of opening and closing brackets
1495  if (*p=='{' || *p=='(' || *p=='[') blevel++ ;
1496  if (*p=='}' || *p==')' || *p==']') blevel-- ;
1497 
1498  // Keep track of string literals
1499  if (*p=='"' || *p=='\'') litmode = !litmode ;
1500 
1501 
1502  // If we encounter a comma at zero bracket level
1503  // finalize the current token as a completed argument
1504  // and start the next token
1505  if (!litmode && blevel==0 && ((*p)==',')) {
1506  *p = 0 ;
1507  args.push_back(tok) ;
1508  tok = p+1 ;
1509  }
1510 
1511  p++ ;
1512  }
1513 
1514  // If the last character was a closing bracket, kill
1515  // it in the buffer
1516  if (p>bufptr && *(p-1)==')') {
1517  *(p-1)=0 ;
1518  }
1519 
1520  // Finalize last token as argument
1521  string tmp = tok ;
1522 
1523  // If there is a suffix left in the work buffer attach it to
1524  // this argument
1525  p = R__STRTOK_R(0,"",&save) ;
1526  if (p) tmp += p ;
1527  args.push_back(tmp) ;
1528 
1529  // Delete the work buffer
1530  delete[] buf ;
1531 
1532  return args ;
1533 }
1534 
1535 
1536 
1537 
1538 
1539 ////////////////////////////////////////////////////////////////////////////////
1540 /// Perform basic syntax on given factory expression. If function returns
1541 /// true syntax errors are found.
1542 
1543 Bool_t RooFactoryWSTool::checkSyntax(const char* arg)
1544 {
1545  // Count parentheses
1546  Int_t nParentheses(0), nBracket(0), nAccolade(0) ;
1547  const char* ptr = arg ;
1548  while(*ptr) {
1549  if (*ptr=='(') nParentheses++ ;
1550  if (*ptr==')') nParentheses-- ;
1551  if (*ptr=='[') nBracket++ ;
1552  if (*ptr==']') nBracket-- ;
1553  if (*ptr=='{') nAccolade++ ;
1554  if (*ptr=='}') nAccolade-- ;
1555  ptr++ ;
1556  }
1557  if (nParentheses!=0) {
1558  coutE(ObjectHandling) << "RooFactoryWSTool::checkSyntax ERROR non-matching '" << (nParentheses>0?"(":")") << "' in expression" << endl ;
1559  return kTRUE ;
1560  }
1561  if (nBracket!=0) {
1562  coutE(ObjectHandling) << "RooFactoryWSTool::checkSyntax ERROR non-matching '" << (nBracket>0?"[":"]") << "' in expression" << endl ;
1563  return kTRUE ;
1564  }
1565  if (nAccolade!=0) {
1566  coutE(ObjectHandling) << "RooFactoryWSTool::checkSyntax ERROR non-matching '" << (nAccolade>0?"{":"}") << "' in expression" << endl ;
1567  return kTRUE ;
1568  }
1569  return kFALSE ;
1570 }
1571 
1572 
1573 
1574 ////////////////////////////////////////////////////////////////////////////////
1575 
1576 void RooFactoryWSTool::checkIndex(UInt_t idx)
1577 {
1578  if (idx>_of->_args.size()-1) {
1579  throw string(Form("Need argument number %d, but only %d args are provided",idx,(Int_t)_of->_args.size())) ;
1580  }
1581 }
1582 
1583 
1584 
1585 ////////////////////////////////////////////////////////////////////////////////
1586 /// CINT constructor interface, return constructor string argument #idx as RooAbsArg reference found in workspace
1587 
1588 RooAbsArg& RooFactoryWSTool::asARG(const char* arg)
1589  {
1590  // If arg is a numeric string, make a RooConst() of it here
1591  if (arg[0]=='.' || arg[0]=='+' || arg[0] == '-' || isdigit(arg[0])) {
1592  return RooConst(atof(arg)) ;
1593  }
1594 
1595  // Otherwise look it up by name in the workspace
1596  RooAbsArg* rarg = ws().arg(arg) ;
1597  if (!rarg) {
1598  throw string(Form("RooAbsArg named %s not found",arg)) ;
1599  }
1600  return *rarg ;
1601 }
1602 
1603 
1604 
1605 ////////////////////////////////////////////////////////////////////////////////
1606 /// CINT constructor interface, return constructor string argument #idx as RooAbsReal reference found in workspace
1607 
1608 RooAbsReal& RooFactoryWSTool::asFUNC(const char* arg)
1609 {
1610  // If arg is a numeric string, make a RooConst() of it here
1611  if (arg[0]=='.' || arg[0]=='+' || arg[0] == '-' || isdigit(arg[0])) {
1612  return RooConst(atof(arg)) ;
1613  }
1614 
1615  RooAbsArg* rarg = ws().arg(arg) ;
1616  if (!rarg) {
1617  throw string(Form("RooAbsReal named %s not found",arg)) ;
1618  }
1619  RooAbsReal* real = dynamic_cast<RooAbsReal*>(rarg) ;
1620  if (!real) {
1621  throw string(Form("Object named %s is not of type RooAbsReal",arg)) ;
1622  }
1623  return *real ;
1624 }
1625 
1626 
1627 
1628 ////////////////////////////////////////////////////////////////////////////////
1629 /// CINT constructor interface, return constructor string argument #idx as RooAbsRealLValue reference found in workspace
1630 
1631 RooAbsRealLValue& RooFactoryWSTool::asVARLV(const char* arg)
1632 {
1633  // If arg is a numeric string, throw error as lvalue is required
1634  if (arg[0]=='.' || arg[0]=='+' || arg[0] == '-' || isdigit(arg[0])) {
1635  throw string(Form("Numeric literal provided for argument (%s), but lvalue is required",arg)) ;
1636  }
1637 
1638  RooAbsArg* rarg = ws().arg(arg) ;
1639  if (!rarg) {
1640  throw string(Form("RooAbsRealLValue named %s not found",arg)) ;
1641  }
1642  RooAbsRealLValue* reallv = dynamic_cast<RooAbsRealLValue*>(rarg) ;
1643  if (!reallv) {
1644  throw string(Form("Object named %s is not of type RooAbsRealLValue",arg)) ;
1645  }
1646  return *reallv ;
1647 }
1648 
1649 
1650 
1651 ////////////////////////////////////////////////////////////////////////////////
1652 /// CINT constructor interface, return constructor string argument #idx as RooRealVar reference found in workspace
1653 
1654 RooRealVar& RooFactoryWSTool::asVAR(const char* arg)
1655 {
1656  RooRealVar* var = ws().var(arg) ;
1657  if (!var) {
1658  throw string(Form("RooRealVar named %s not found",arg)) ;
1659  }
1660  return *var ;
1661 }
1662 
1663 
1664 
1665 
1666 ////////////////////////////////////////////////////////////////////////////////
1667 /// CINT constructor interface, return constructor string argument #idx as RooAbsPdf reference found in workspace
1668 
1669 RooAbsPdf& RooFactoryWSTool::asPDF(const char* arg)
1670 {
1671  RooAbsPdf* pdf = ws().pdf(arg) ;
1672  if (!pdf) {
1673  throw string(Form("RooAbsPdf named %s not found",arg)) ;
1674  }
1675  return *pdf ;
1676 }
1677 
1678 
1679 
1680 
1681 ////////////////////////////////////////////////////////////////////////////////
1682 /// CINT constructor interface, return constructor string argument #idx as RooResolutionModel reference found in workspace
1683 
1684 RooResolutionModel& RooFactoryWSTool::asRMODEL(const char* arg)
1685 {
1686  RooAbsArg* rarg = ws().arg(arg) ;
1687  if (!rarg) {
1688  throw string(Form("RooResolutionModel named %s not found",arg)) ;
1689  }
1690  RooResolutionModel * rmodel = dynamic_cast<RooResolutionModel*>(rarg) ;
1691  if (!rmodel) {
1692  throw string(Form("Object named %s is not of type RooResolutionModel",arg)) ;
1693  }
1694  return *rmodel ;
1695 }
1696 
1697 
1698 
1699 
1700 ////////////////////////////////////////////////////////////////////////////////
1701 /// CINT constructor interface, return constructor string argument #idx as RooAbsCategory reference found in workspace
1702 
1703 RooAbsCategory& RooFactoryWSTool::asCATFUNC(const char* arg)
1704 {
1705  RooAbsArg* rarg = ws().arg(arg) ;
1706  if (!rarg) {
1707  throw string(Form("RooAbsCategory named %s not found",arg)) ;
1708  }
1709  RooAbsCategory* catf = dynamic_cast<RooAbsCategory*>(rarg) ;
1710  if (!catf) {
1711  throw string(Form("Object named %s is not of type RooAbsCategory",arg)) ;
1712  }
1713  return *catf ;
1714 }
1715 
1716 
1717 
1718 ////////////////////////////////////////////////////////////////////////////////
1719 /// CINT constructor interface, return constructor string argument #idx as RooAbsCategoryLValue reference found in workspace
1720 
1721 RooAbsCategoryLValue& RooFactoryWSTool::asCATLV(const char* arg)
1722 {
1723  RooAbsArg* rarg = ws().arg(arg) ;
1724  if (!rarg) {
1725  throw string(Form("RooAbsCategoryLValue named %s not found",arg)) ;
1726  }
1727 
1728  RooAbsCategoryLValue* catlv = dynamic_cast<RooAbsCategoryLValue*>(rarg) ;
1729  if (!catlv) {
1730  throw string(Form("Object named %s is not of type RooAbsCategoryLValue",arg)) ;
1731  }
1732  return *catlv ;
1733 }
1734 
1735 
1736 
1737 ////////////////////////////////////////////////////////////////////////////////
1738 /// CINT constructor interface, return constructor string argument #idx as RooCategory reference found in workspace
1739 
1740 RooCategory& RooFactoryWSTool::asCAT(const char* arg)
1741 {
1742  RooCategory* cat = ws().cat(arg) ;
1743  if (!cat) {
1744  throw string(Form("RooCategory named %s not found",arg)) ;
1745  }
1746  return *cat ;
1747 }
1748 
1749 
1750 
1751 
1752 
1753 ////////////////////////////////////////////////////////////////////////////////
1754 /// CINT constructor interface, return constructor string argument #idx as RooArgSet of objects found in workspace
1755 
1756 RooArgSet RooFactoryWSTool::asSET(const char* arg)
1757 {
1758  char tmp[BUFFER_SIZE] ;
1759  strlcpy(tmp,arg,BUFFER_SIZE) ;
1760 
1761  RooArgSet s ;
1762 
1763  // If given object is not of {,,,} form, interpret given string as name of defined set
1764  if (arg[0]!='{') {
1765  // cout << "asSet(arg='" << arg << "') parsing as defined set" << endl ;
1766  const RooArgSet* defSet = ws().set(arg) ;
1767  if (defSet) {
1768  // cout << "found defined set: " << *defSet << endl ;
1769  s.add(*defSet) ;
1770  return s ;
1771  }
1772  }
1773 
1774  char* save ;
1775  char* tok = R__STRTOK_R(tmp,",{}",&save) ;
1776  int i(0);
1777  while(tok) {
1778 
1779  // If arg is a numeric string, make a RooConst() of it here
1780  if (tok[0]=='.' || tok[0]=='+' || tok[0] == '-' || isdigit(tok[0])) {
1781  s.add(RooConst(atof(tok))) ;
1782  } else if (tok[0] == '\'') {
1783  tok[strlen(tok) - 1] = 0;
1784  RooStringVar *sv = new RooStringVar(Form("string_set_item%03d", i++), "string_set_item", tok + 1);
1785  s.add(*sv);
1786  } else {
1787  RooAbsArg* aarg = ws().arg(tok) ;
1788  if (aarg) {
1789  s.add(*aarg) ;
1790  } else {
1791  throw string(Form("RooAbsArg named %s not found",tok)) ;
1792  }
1793  }
1794  tok = R__STRTOK_R(0,",{}",&save) ;
1795  }
1796 
1797  return s ;
1798 }
1799 
1800 
1801 
1802 ////////////////////////////////////////////////////////////////////////////////
1803 /// CINT constructor interface, return constructor string argument #idx as RooArgList of objects found in workspace
1804 
1805 RooArgList RooFactoryWSTool::asLIST(const char* arg)
1806 {
1807  char tmp[BUFFER_SIZE] ;
1808  strlcpy(tmp,arg,BUFFER_SIZE) ;
1809 
1810  RooArgList l ;
1811  char* save ;
1812  char* tok = R__STRTOK_R(tmp,",{}",&save) ;
1813  while(tok) {
1814 
1815  // If arg is a numeric string, make a RooConst() of it here
1816  if (tok[0]=='.' || tok[0]=='+' || tok[0] == '-' || isdigit(tok[0])) {
1817  l.add(RooConst(atof(tok))) ;
1818  } else if (tok[0] == '\'') {
1819  tok[strlen(tok) - 1] = 0;
1820  RooStringVar *sv = new RooStringVar("listarg", "listarg", tok + 1);
1821  l.add(*sv);
1822  } else {
1823  RooAbsArg* aarg = ws().arg(tok) ;
1824  if (aarg) {
1825  l.add(*aarg) ;
1826  } else {
1827  throw string(Form("RooAbsArg named %s not found",tok)) ;
1828  }
1829  }
1830  tok = R__STRTOK_R(0,",{}",&save) ;
1831  }
1832 
1833  return l ;
1834 }
1835 
1836 
1837 
1838 ////////////////////////////////////////////////////////////////////////////////
1839 /// CINT constructor interface, return constructor string argument #idx as RooAbsData object found in workspace
1840 
1841 RooAbsData& RooFactoryWSTool::asDATA(const char* arg)
1842 {
1843  RooAbsData* data = ws().data(arg) ;
1844  if (!data) {
1845  throw string(Form("RooAbsData named %s not found",arg)) ;
1846  }
1847  return *data ;
1848 }
1849 
1850 
1851 
1852 ////////////////////////////////////////////////////////////////////////////////
1853 /// CINT constructor interface, return constructor string argument #idx as RooDataHist object found in workspace
1854 
1855 RooDataHist& RooFactoryWSTool::asDHIST(const char* arg)
1856 {
1857  RooAbsData* data = ws().data(arg) ;
1858  if (!data) {
1859  throw string(Form("RooAbsData named %s not found",arg)) ;
1860  }
1861  RooDataHist* hist = dynamic_cast<RooDataHist*>(data) ;
1862  if (!hist) {
1863  throw string(Form("Dataset named %s is not of type RooDataHist",arg)) ;
1864  }
1865  return *hist ;
1866 }
1867 
1868 
1869 ////////////////////////////////////////////////////////////////////////////////
1870 /// CINT constructor interface, return constructor string argument #idx as RooDataSet object found in workspace
1871 
1872 RooDataSet& RooFactoryWSTool::asDSET(const char* arg)
1873 {
1874  RooAbsData* data = ws().data(arg) ;
1875  if (!data) {
1876  throw string(Form("RooAbsData named %s not found",arg)) ;
1877  }
1878  RooDataSet* dset = dynamic_cast<RooDataSet*>(data) ;
1879  if (!dset) {
1880  throw string(Form("Dataset named %s is not of type RooDataSet",arg)) ;
1881  }
1882  return *dset ;
1883 }
1884 
1885 
1886 
1887 ////////////////////////////////////////////////////////////////////////////////
1888 
1889 TObject& RooFactoryWSTool::asOBJ(const char* arg)
1890 {
1891  TObject* obj = ws().obj(arg) ;
1892  if (!obj) {
1893  throw string(Form("Object named %s not found",arg)) ;
1894  }
1895  return *obj ;
1896 }
1897 
1898 
1899 
1900 ////////////////////////////////////////////////////////////////////////////////
1901 /// CINT constructor interface, return constructor string argument #idx as const char*
1902 
1903 const char* RooFactoryWSTool::asSTRING(const char* arg)
1904 {
1905  static vector<string> cbuf(10) ;
1906  static unsigned int cbuf_idx = 0 ;
1907 
1908  // Handle empty string case: return null pointer
1909  if (arg==0 || strlen(arg)==0) {
1910  return 0 ;
1911  }
1912 
1913  // Fill cyclical buffer entry with quotation marked stripped version of string literal
1914  // and return pointer to stripped buffer
1915  cbuf[cbuf_idx].clear() ;
1916  const char* p = arg+1 ;
1917  while(*p && (*p) != '"' && (*p) !='\'' ) {
1918  cbuf[cbuf_idx] += *(p++) ;
1919  }
1920  const char* ret = cbuf[cbuf_idx].c_str() ;
1921 
1922  // Increment buffer pointer by one
1923  cbuf_idx++ ;
1924  if (cbuf_idx==cbuf.size()) cbuf_idx=0 ;
1925 
1926  return ret ;
1927 }
1928 
1929 
1930 ////////////////////////////////////////////////////////////////////////////////
1931 /// CINT constructor interface, return constructor string argument #idx as Int_t
1932 
1933 Int_t RooFactoryWSTool::asINT(const char* arg)
1934 {
1935  return atoi(arg) ;
1936 }
1937 
1938 
1939 ////////////////////////////////////////////////////////////////////////////////
1940 /// CINT constructor interface, return constructor string argument #idx as Double_t
1941 
1942 Double_t RooFactoryWSTool::asDOUBLE(const char* arg)
1943 {
1944  return atof(arg) ;
1945 }
1946 
1947 
1948 ////////////////////////////////////////////////////////////////////////////////
1949 /// Register foreign special objects in factory
1950 
1951 void RooFactoryWSTool::registerSpecial(const char* typeName, RooFactoryWSTool::IFace* iface)
1952 {
1953  hooks()[typeName] = iface ;
1954 }
1955 
1956 
1957 
1958 ////////////////////////////////////////////////////////////////////////////////
1959 
1960 std::map<std::string,RooFactoryWSTool::IFace*>& RooFactoryWSTool::hooks()
1961 {
1962  if (_hooks) return *_hooks ;
1963  _hooks = new map<string,IFace*> ;
1964  return *_hooks ;
1965 }
1966 
1967 
1968 
1969 ////////////////////////////////////////////////////////////////////////////////
1970 /// Concatenate list of args into comma separated string
1971 
1972 std::string RooFactoryWSTool::SpecialsIFace::create(RooFactoryWSTool& ft, const char* typeName, const char* instName, std::vector<std::string> args)
1973 {
1974  char pargs[BUFFER_SIZE] ;
1975  pargs[0] = 0 ;
1976  vector<string>::iterator iter = args.begin() ;
1977  vector<string> pargv ;
1978  while(iter!=args.end()) {
1979  if (strlen(pargs)>0) strlcat(pargs,",",BUFFER_SIZE) ;
1980  string tmp = ft.processExpression(iter->c_str()) ;
1981  strlcat(pargs,tmp.c_str(),BUFFER_SIZE) ;
1982  pargv.push_back(tmp) ;
1983  ++iter ;
1984  }
1985 
1986  // Handling of special operator pdf class names
1987  string cl(typeName) ;
1988  if (cl=="SUM") {
1989 
1990  // SUM::name[a*A,b*B,C]
1991  ft.add(instName,pargs,kFALSE) ;
1992 
1993  } else if (cl=="RSUM") {
1994 
1995  // RSUM::name[a*A,b*B,C]
1996  ft.add(instName,pargs,kTRUE) ;
1997 
1998  } else if (cl=="ASUM") {
1999 
2000  // ASUM::name[a*A,b*B,C]
2001  ft.amplAdd(instName,pargs) ;
2002 
2003  } else if (cl=="PROD") {
2004 
2005  // PROD::name[A,B,C]
2006  ft.prod(instName,pargs) ;
2007 
2008  } else if (cl=="SIMUL") {
2009 
2010  // PROD::name[cat,state=Pdf,...]
2011  if (pargv.size()>1) {
2012  ft.simul(instName,pargv[0].c_str(),strchr(pargs,',')+1) ;
2013  } else {
2014  throw string(Form("Need at least two arguments in call to SIMUL::%s, have %d: %s",instName,(Int_t)pargv.size(),pargs)) ;
2015  }
2016 
2017  } else if (cl=="EXPR") {
2018 
2019  // EXPR::name['expr',var,var,...]
2020  if (args.size()<=2) {
2021  ft.createArg("RooGenericPdf",instName,pargs) ;
2022  } else {
2023  char genargs[BUFFER_SIZE] ;
2024  strlcpy(genargs,args[0].c_str(),BUFFER_SIZE) ;
2025  strlcat(genargs,",{",BUFFER_SIZE) ;
2026  for (UInt_t i=1 ; i<args.size() ; i++) {
2027  if (i!=1) strlcat(genargs,",",BUFFER_SIZE) ;
2028  strlcat(genargs,args[i].c_str(),BUFFER_SIZE) ;
2029  }
2030  strlcat(genargs,"}",BUFFER_SIZE) ;
2031  ft.createArg("RooGenericPdf",instName,genargs) ;
2032  }
2033 
2034  } else if (cl=="FCONV") {
2035 
2036  // FCONV::name[var,pdf1,pdf2]
2037  ft.createArg("RooFFTConvPdf",instName,pargs) ;
2038 
2039  } else if (cl=="NCONV") {
2040 
2041  // NCONV::name[var,pdf1,pdf2]
2042  ft.createArg("RooNumConvPdf",instName,pargs) ;
2043 
2044  } else if (cl=="sum") {
2045 
2046  // sum::name[a,b,c]
2047  ft.addfunc(instName,pargs) ;
2048 
2049  } else if (cl=="prod") {
2050 
2051  // prod::name[a,b,c]
2052  ft.prodfunc(instName,pargs) ;
2053 
2054  } else if (cl=="expr") {
2055 
2056  // expr::name['expr',var,var,...]
2057  if (args.size()<=2) {
2058  ft.createArg("RooFormulaVar",instName,pargs) ;
2059  } else {
2060  char genargs[BUFFER_SIZE] ;
2061  strlcpy(genargs,args[0].c_str(),BUFFER_SIZE) ;
2062  strlcat(genargs,",{",BUFFER_SIZE) ;
2063  for (UInt_t i=1 ; i<args.size() ; i++) {
2064  if (i!=1) strlcat(genargs,",",BUFFER_SIZE) ;
2065  strlcat(genargs,args[i].c_str(),BUFFER_SIZE) ;
2066  }
2067  strlcat(genargs,"}",BUFFER_SIZE) ;
2068  ft.createArg("RooFormulaVar",instName,genargs) ;
2069  }
2070 
2071  } else if (cl=="nconv") {
2072 
2073  // nconv::name[var,pdf1,pdf2]
2074  ft.createArg("RooNumConvolution",instName,pargs) ;
2075 
2076  } else if (cl=="nll") {
2077 
2078  // nll::name[pdf,data]
2079  RooNLLVar nll(instName,instName,ft.asPDF(pargv[0].c_str()),ft.asDATA(pargv[1].c_str())) ;
2080  if (ft.ws().import(nll,Silence())) ft.logError() ;
2081 
2082  } else if (cl=="chi2") {
2083 
2084  // chi2::name[pdf,data]
2085  RooChi2Var nll(instName,instName,ft.asPDF(pargv[0].c_str()),ft.asDHIST(pargv[1].c_str())) ;
2086  if (ft.ws().import(nll,Silence())) ft.logError() ;
2087 
2088  } else if (cl=="profile") {
2089 
2090  // profile::name[func,vars]
2091  ft.createArg("RooProfileLL",instName,pargs) ;
2092 
2093  } else if (cl=="dataobs") {
2094 
2095  // dataobs::name[dset,func]
2096  RooAbsArg* funcClone = static_cast<RooAbsArg*>(ft.asARG(pargv[1].c_str()).clone(instName)) ;
2097  RooAbsArg* arg = ft.asDSET(pargv[0].c_str()).addColumn(*funcClone) ;
2098  if (!ft.ws().fundArg(arg->GetName())) {
2099  if (ft.ws().import(*arg,Silence())) ft.logError() ;
2100  }
2101  delete funcClone ;
2102 
2103  } else if (cl=="int") {
2104 
2105  // int::name[func,intobs]
2106  // int::name[func,intobs|range]
2107  // int::name[func,intobs,normobs]
2108  // int::name[func,intobs|range,normobs]
2109 
2110  if (pargv.size()<2 || pargv.size()>3) {
2111  throw string(Form("int::%s, requires 2 or 3 arguments, have %d arguments",instName,(Int_t)pargv.size())) ;
2112  }
2113 
2114  RooAbsReal& func = ft.asFUNC(pargv[0].c_str()) ;
2115 
2116  char buf[256] ;
2117  strlcpy(buf,pargv[1].c_str(),256) ;
2118  char* save ;
2119  const char* intobs = R__STRTOK_R(buf,"|",&save) ;
2120  if (!intobs) intobs="" ;
2121 
2122  const char* range = R__STRTOK_R(0,"",&save) ;
2123  if (!range) range="" ;
2124 
2125  RooAbsReal* integral = 0 ;
2126  if (pargv.size()==2) {
2127  if (range && strlen(range)) {
2128  integral = func.createIntegral(ft.asSET(intobs),Range(range)) ;
2129  } else {
2130  integral = func.createIntegral(ft.asSET(intobs)) ;
2131  }
2132  } else {
2133  if (range && strlen(range)) {
2134  integral = func.createIntegral(ft.asSET(intobs),Range(range),NormSet(ft.asSET(pargv[2].c_str()))) ;
2135  } else {
2136  integral = func.createIntegral(ft.asSET(intobs),NormSet(ft.asSET(pargv[2].c_str()))) ;
2137  }
2138  }
2139 
2140  integral->SetName(instName) ;
2141  if (ft.ws().import(*integral,Silence())) ft.logError() ;
2142 
2143  } else if (cl=="deriv") {
2144 
2145  // derive::name[func,obs,order]
2146 
2147  if (pargv.size()<2 || pargv.size()>3) {
2148  throw string(Form("deriv::%s, requires 2 or 3 arguments, have %d arguments",instName,(Int_t)pargv.size())) ;
2149  }
2150 
2151  RooAbsReal& func = ft.asFUNC(pargv[0].c_str()) ;
2152 
2153  RooAbsReal* derivative(0) ;
2154  if (pargv.size()==2) {
2155  derivative = func.derivative(ft.asVAR(pargv[1].c_str()),1) ;
2156  } else {
2157  derivative = func.derivative(ft.asVAR(pargv[1].c_str()),ft.asINT(pargv[2].c_str())) ;
2158  }
2159 
2160  derivative->SetName(instName) ;
2161  if (ft.ws().import(*derivative,Silence())) ft.logError() ;
2162 
2163  } else if (cl=="cdf") {
2164 
2165  // cdf::name[pdf,obs,extranormobs]
2166 
2167  if (pargv.size()<2 || pargv.size()>3) {
2168  throw string(Form("cdf::%s, requires 2 or 3 arguments, have %d arguments",instName,(Int_t)pargv.size())) ;
2169  }
2170 
2171  RooAbsPdf& pdf = ft.asPDF(pargv[0].c_str()) ;
2172 
2173  RooAbsReal* cdf(0) ;
2174  if (pargv.size()==2) {
2175  cdf = pdf.createCdf(ft.asSET(pargv[1].c_str())) ;
2176  } else {
2177  cdf = pdf.createCdf(ft.asSET(pargv[1].c_str()),ft.asSET(pargv[2].c_str())) ;
2178  }
2179 
2180  cdf->SetName(instName) ;
2181  if (ft.ws().import(*cdf,Silence())) ft.logError() ;
2182 
2183 
2184  } else if (cl=="PROJ") {
2185 
2186  // PROJ::name(pdf,intobs)
2187  if (pargv.size()!=2) {
2188  throw string(Form("PROJ::%s, requires 2 arguments, have %d arguments",instName,(Int_t)pargv.size())) ;
2189  }
2190 
2191  RooAbsPdf& pdf = ft.asPDF(pargv[0].c_str()) ;
2192  RooAbsPdf* projection = pdf.createProjection(ft.asSET(pargv[1].c_str())) ;
2193  projection->SetName(instName) ;
2194 
2195  if (ft.ws().import(*projection,Silence())) ft.logError() ;
2196 
2197  } else if (cl=="set") {
2198 
2199  // set::name(arg,arg,...)
2200  if (ft.ws().defineSet(instName,pargs)) {
2201  ft.logError() ;
2202  return string(instName) ;
2203  }
2204 
2205  } else {
2206 
2207  throw string(Form("RooFactoryWSTool::SpecialsIFace::create() ERROR: Unknown meta-type %s",typeName)) ;
2208 
2209  }
2210  return string(instName) ;
2211 }
2212 
2213 
2214 RooFactoryWSTool* RooFactoryWSTool::of()
2215 {
2216  return _of ;
2217 }
2218