Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooClassFactory.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 RooClassFactory.cxx
19 \class RooClassFactory
20 \ingroup Roofitcore
21 
22 RooClassFactory 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 #include "TClass.h"
31 #include "RooClassFactory.h"
32 #include "RooErrorHandler.h"
33 #include "RooAbsReal.h"
34 #include "RooAbsCategory.h"
35 #include "RooArgList.h"
36 #include "RooMsgService.h"
37 #include "TInterpreter.h"
38 #include "RooWorkspace.h"
39 #include "RooGlobalFunc.h"
40 #include "RooAbsPdf.h"
41 #include <fstream>
42 
43 using namespace std ;
44 
45 ClassImp(RooClassFactory);
46 ;
47 
48 static Int_t init();
49 
50 static Int_t dummy = init() ;
51 
52 static Int_t init()
53 {
54  RooFactoryWSTool::IFace* iface = new RooClassFactory::ClassFacIFace ;
55  RooFactoryWSTool::registerSpecial("CEXPR",iface) ;
56  RooFactoryWSTool::registerSpecial("cexpr",iface) ;
57  (void)dummy;
58  return 0 ;
59 }
60 
61 
62 
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 /// Default constructor
66 
67 RooClassFactory::RooClassFactory()
68 {
69 }
70 
71 
72 
73 ////////////////////////////////////////////////////////////////////////////////
74 /// Destructor
75 
76 RooClassFactory::~RooClassFactory()
77 {
78 }
79 
80 
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 
84 Bool_t RooClassFactory::makeAndCompilePdf(const char* name, const char* expression, const RooArgList& vars, const char* intExpression)
85 {
86  string realArgNames,catArgNames ;
87  TIterator* iter = vars.createIterator() ;
88  RooAbsArg* arg ;
89  while((arg=(RooAbsArg*)iter->Next())) {
90  if (dynamic_cast<RooAbsReal*>(arg)) {
91  if (realArgNames.size()>0) realArgNames += "," ;
92  realArgNames += arg->GetName() ;
93  } else if (dynamic_cast<RooAbsCategory*>(arg)) {
94  if (catArgNames.size()>0) catArgNames += "," ;
95  catArgNames += arg->GetName() ;
96  } else {
97  oocoutE((RooAbsArg*)0,InputArguments) << "RooClassFactory::makeAndCompilePdf ERROR input argument " << arg->GetName()
98  << " is neither RooAbsReal nor RooAbsCategory and is ignored" << endl ;
99  }
100  }
101  delete iter ;
102 
103  Bool_t ret = makePdf(name,realArgNames.c_str(),catArgNames.c_str(),expression,intExpression?kTRUE:kFALSE,kFALSE,intExpression) ;
104  if (ret) {
105  return ret ;
106  }
107 
108  TInterpreter::EErrorCode ecode;
109  gInterpreter->ProcessLineSynch(Form(".L %s.cxx+",name),&ecode) ;
110  return (ecode!=TInterpreter::kNoError) ;
111 }
112 
113 
114 
115 ////////////////////////////////////////////////////////////////////////////////
116 /// Write, compile and load code for a RooAbsReal implementation with
117 /// class name 'name', taking all elements of 'vars' as constructor
118 /// arguments. The initial value expression is taken to be
119 /// 'expression' which can be any one-line C++ expression in terms of
120 /// variables that occur in 'vars'. You can add optional expressions
121 /// for analytical integrals to be advertised by your class in the
122 /// syntax
123 /// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
124 /// where <intObsName> a name of the observable integrated over and
125 /// <CPPAnaIntExpression> is the C++ expression that calculates that
126 /// integral.
127 
128 Bool_t RooClassFactory::makeAndCompileFunction(const char* name, const char* expression, const RooArgList& vars, const char* intExpression)
129 {
130  string realArgNames,catArgNames ;
131  TIterator* iter = vars.createIterator() ;
132  RooAbsArg* arg ;
133  while((arg=(RooAbsArg*)iter->Next())) {
134  if (dynamic_cast<RooAbsReal*>(arg)) {
135  if (realArgNames.size()>0) realArgNames += "," ;
136  realArgNames += arg->GetName() ;
137  } else if (dynamic_cast<RooAbsCategory*>(arg)) {
138  if (catArgNames.size()>0) catArgNames += "," ;
139  catArgNames += arg->GetName() ;
140  } else {
141  oocoutE((RooAbsArg*)0,InputArguments) << "RooClassFactory::makeAndCompileFunction ERROR input argument " << arg->GetName()
142  << " is neither RooAbsReal nor RooAbsCategory and is ignored" << endl ;
143  }
144  }
145  delete iter ;
146 
147  Bool_t ret = makeFunction(name,realArgNames.c_str(),catArgNames.c_str(),expression,intExpression?kTRUE:kFALSE,intExpression) ;
148  if (ret) {
149  return ret ;
150  }
151 
152  TInterpreter::EErrorCode ecode;
153  gInterpreter->ProcessLineSynch(Form(".L %s.cxx+",name),&ecode) ;
154  return (ecode!=TInterpreter::kNoError) ;
155 }
156 
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 /// Write, compile and load code and instantiate object for a
160 /// RooAbsReal implementation with class name 'name', taking all
161 /// elements of 'vars' as constructor arguments. The initial value
162 /// expression is taken to be 'expression' which can be any one-line
163 /// C++ expression in terms of variables that occur in 'vars'.
164 ///
165 /// The returned object is an instance of the object you just defined
166 /// connected to the variables listed in 'vars'. The name of the
167 /// object is 'name', its class name Roo<name>Class.
168 ///
169 /// This function is an effective compiled replacement of RooFormulaVar
170 ///
171 /// You can add optional expressions for analytical integrals to be
172 /// advertised by your class in the syntax
173 /// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
174 /// where <intObsName> a name of the observable integrated over and
175 /// <CPPAnaIntExpression> is the C++ expression that calculates that
176 /// integral.
177 
178 RooAbsReal* RooClassFactory::makeFunctionInstance(const char* name, const char* expression, const RooArgList& vars, const char* intExpression)
179 {
180  // Construct unique class name for this function expression
181  string tmpName(name) ;
182  tmpName[0] = toupper(tmpName[0]) ;
183  string className = Form("Roo%sFunc",tmpName.c_str()) ;
184 
185  return makeFunctionInstance(className.c_str(),name,expression,vars,intExpression) ;
186 }
187 
188 ////////////////////////////////////////////////////////////////////////////////
189 /// Write, compile and load code and instantiate object for a
190 /// RooAbsReal implementation with class name 'name', taking all
191 /// elements of 'vars' as constructor arguments. The initial value
192 /// expression is taken to be 'expression' which can be any one-line
193 /// C++ expression in terms of variables that occur in 'vars'.
194 ///
195 /// The returned object is an instance of the object you just defined
196 /// connected to the variables listed in 'vars'. The name of the
197 /// object is 'name', its class name Roo<name>Class.
198 ///
199 /// This function is an effective compiled replacement of RooFormulaVar
200 ///
201 /// You can add optional expressions for analytical integrals to be
202 /// advertised by your class in the syntax
203 /// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
204 /// where <intObsName> a name of the observable integrated over and
205 /// <CPPAnaIntExpression> is the C++ expression that calculates that
206 /// integral.
207 
208 RooAbsReal* RooClassFactory::makeFunctionInstance(const char* className, const char* name, const char* expression, const RooArgList& vars, const char* intExpression)
209 {
210  // Use class factory to compile and link specialized function
211  Bool_t error = makeAndCompileFunction(className,expression,vars,intExpression) ;
212 
213  // Check that class was created OK
214  if (error) {
215  RooErrorHandler::softAbort() ;
216  }
217 
218  // Create CINT line that instantiates specialized object
219  string line = Form("new %s(\"%s\",\"%s\"",className,name,name) ;
220 
221  // Make list of pointer values (represented in hex ascii) to be passed to cint
222  // Note that the order of passing arguments must match the convention in which
223  // the class code is generated: first all reals, then all categories
224 
225  TIterator* iter = vars.createIterator() ;
226  string argList ;
227  // First pass the RooAbsReal arguments in the list order
228  RooAbsArg* var ;
229  while((var=(RooAbsArg*)iter->Next())) {
230  if (dynamic_cast<RooAbsReal*>(var)) {
231  argList += Form(",*((RooAbsReal*)0x%lx)",(ULong_t)var) ;
232  }
233  }
234  iter->Reset() ;
235  // Next pass the RooAbsCategory arguments in the list order
236  while((var=(RooAbsArg*)iter->Next())) {
237  if (dynamic_cast<RooAbsCategory*>(var)) {
238  argList += Form(",*((RooAbsCategory*)0x%lx)",(ULong_t)var) ;
239  }
240  }
241  delete iter ;
242 
243  line += argList + ") ;" ;
244 
245  // Let CINT instantiate specialized formula
246  return (RooAbsReal*) gInterpreter->ProcessLineSynch(line.c_str()) ;
247 }
248 
249 
250 
251 
252 ////////////////////////////////////////////////////////////////////////////////
253 /// Write, compile and load code and instantiate object for a
254 /// RooAbsPdf implementation with class name 'name', taking all
255 /// elements of 'vars' as constructor arguments. The initial value
256 /// expression is taken to be 'expression' which can be any one-line
257 /// C++ expression in terms of variables that occur in 'vars'.
258 ///
259 /// The returned object is an instance of the object you just defined
260 /// connected to the variables listed in 'vars'. The name of the
261 /// object is 'name', its class name Roo<name>Class.
262 ///
263 /// This function is an effective compiled replacement of RooGenericPdf
264 ///
265 /// You can add optional expressions for analytical integrals to be
266 /// advertised by your class in the syntax
267 /// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
268 /// where <intObsName> a name of the observable integrated over and
269 /// <CPPAnaIntExpression> is the C++ expression that calculates that
270 /// integral.
271 
272 RooAbsPdf* RooClassFactory::makePdfInstance(const char* name, const char* expression,
273  const RooArgList& vars, const char* intExpression)
274 {
275  // Construct unique class name for this function expression
276  string tmpName(name) ;
277  tmpName[0] = toupper(tmpName[0]) ;
278  string className = Form("Roo%sPdf",tmpName.c_str()) ;
279 
280  return makePdfInstance(className.c_str(),name,expression,vars,intExpression) ;
281 }
282 
283 ////////////////////////////////////////////////////////////////////////////////
284 /// Write, compile and load code and instantiate object for a
285 /// RooAbsPdf implementation with class name 'name', taking all
286 /// elements of 'vars' as constructor arguments. The initial value
287 /// expression is taken to be 'expression' which can be any one-line
288 /// C++ expression in terms of variables that occur in 'vars'.
289 ///
290 /// The returned object is an instance of the object you just defined
291 /// connected to the variables listed in 'vars'. The name of the
292 /// object is 'name', its class name Roo<name>Class.
293 ///
294 /// This function is an effective compiled replacement of RooGenericPdf
295 ///
296 /// You can add optional expressions for analytical integrals to be
297 /// advertised by your class in the syntax
298 /// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
299 /// where <intObsName> a name of the observable integrated over and
300 /// <CPPAnaIntExpression> is the C++ expression that calculates that
301 /// integral.
302 
303 RooAbsPdf* RooClassFactory::makePdfInstance(const char* className, const char* name, const char* expression,
304  const RooArgList& vars, const char* intExpression)
305 {
306  // Use class factory to compile and link specialized function
307  Bool_t error = makeAndCompilePdf(className,expression,vars,intExpression) ;
308 
309  // Check that class was created OK
310  if (error) {
311  RooErrorHandler::softAbort() ;
312  }
313 
314  // Create CINT line that instantiates specialized object
315  string line = Form("new %s(\"%s\",\"%s\"",className,name,name) ;
316 
317  // Make list of pointer values (represented in hex ascii) to be passed to cint
318  // Note that the order of passing arguments must match the convention in which
319  // the class code is generated: first all reals, then all categories
320 
321  TIterator* iter = vars.createIterator() ;
322  string argList ;
323  // First pass the RooAbsReal arguments in the list order
324  RooAbsArg* var ;
325  while((var=(RooAbsArg*)iter->Next())) {
326  if (dynamic_cast<RooAbsReal*>(var)) {
327  argList += Form(",*((RooAbsReal*)0x%lx)",(ULong_t)var) ;
328  }
329  }
330  iter->Reset() ;
331  // Next pass the RooAbsCategory arguments in the list order
332  while((var=(RooAbsArg*)iter->Next())) {
333  if (dynamic_cast<RooAbsCategory*>(var)) {
334  argList += Form(",*((RooAbsCategory*)0x%lx)",(ULong_t)var) ;
335  }
336  }
337  delete iter ;
338 
339  line += argList + ") ;" ;
340 
341  // Let CINT instantiate specialized formula
342  return (RooAbsPdf*) gInterpreter->ProcessLineSynch(line.c_str()) ;
343 }
344 
345 
346 
347 ////////////////////////////////////////////////////////////////////////////////
348 /// Write code for a RooAbsPdf implementation with class name 'name',
349 /// taking RooAbsReal arguments with names listed in argNames and
350 /// RooAbsCategory arguments with names listed in catArgNames as
351 /// constructor arguments (use a comma separated list for multiple
352 /// arguments). The initial value expression is taken to be
353 /// 'expression' which can be any one-line C++ expression in terms of
354 /// variables that occur in 'vars'. Skeleton code for handling of
355 /// analytical integrals is added if hasAnaInt is true. You can add
356 /// optional expressions for analytical integrals to be advertised by
357 /// your class in the syntax
358 /// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
359 /// where <intObsName> a name of the observable integrated over and
360 /// <CPPAnaIntExpression> is the C++ expression that calculates that
361 /// integral. Skeleton code for internal event generation is added
362 /// if hasIntGen is true
363 ///
364 
365 Bool_t RooClassFactory::makePdf(const char* name, const char* argNames, const char* catArgNames, const char* expression,
366  Bool_t hasAnaInt, Bool_t hasIntGen, const char* intExpression)
367 {
368  return makeClass("RooAbsPdf",name,argNames,catArgNames,expression,hasAnaInt,hasIntGen,intExpression) ;
369 }
370 
371 
372 ////////////////////////////////////////////////////////////////////////////////
373 /// Write code for a RooAbsReal implementation with class name 'name',
374 /// taking RooAbsReal arguments with names listed in argNames and
375 /// RooAbsCategory arguments with names listed in catArgNames as
376 /// constructor arguments (use a comma separated list for multiple
377 /// arguments). The initial value expression is taken to be
378 /// 'expression' which can be any one-line C++ expression in terms of
379 /// variables that occur in 'vars'. Skeleton code for handling of
380 /// analytical integrals is added if hasAnaInt is true. You can add
381 /// optional expressions for analytical integrals to be advertised by
382 /// your class in the syntax
383 /// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
384 /// where <intObsName> a name of the observable integrated over and
385 /// <CPPAnaIntExpression> is the C++ expression that calculates that
386 /// integral.
387 
388 Bool_t RooClassFactory::makeFunction(const char* name, const char* argNames, const char* catArgNames, const char* expression, Bool_t hasAnaInt, const char* intExpression)
389 {
390  return makeClass("RooAbsReal",name,argNames,catArgNames,expression,hasAnaInt,kFALSE,intExpression) ;
391 }
392 
393 
394 ////////////////////////////////////////////////////////////////////////////////
395 /// Write code for a 'baseName' implementation with class name 'className',
396 /// taking RooAbsReal arguments with names listed in argNames and
397 /// RooAbsCategory arguments with names listed in catArgNames as
398 /// constructor arguments (use a comma separated list for multiple
399 /// arguments). The initial value expression is taken to be
400 /// 'expression' which can be any one-line C++ expression in terms of
401 /// variables that occur in 'vars'. Skeleton code for handling of
402 /// analytical integrals is added if hasAnaInt is true. You can add
403 /// optional expressions for analytical integrals to be advertised by
404 /// your class in the syntax
405 /// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
406 /// where <intObsName> a name of the observable integrated over and
407 /// <CPPAnaIntExpression> is the C++ expression that calculates that
408 /// integral. Skeleton code for internal event generation is added
409 /// if hasIntGen is true
410 ///
411 
412 Bool_t RooClassFactory::makeClass(const char* baseName, const char* className, const char* realArgNames, const char* catArgNames,
413  const char* expression, Bool_t hasAnaInt, Bool_t hasIntGen, const char* intExpression)
414 {
415  // Check that arguments were given
416  if (!baseName) {
417  oocoutE((TObject*)0,InputArguments) << "RooClassFactory::makeClass: ERROR: a base class name must be given" << endl ;
418  return kTRUE ;
419  }
420 
421  if (!className) {
422  oocoutE((TObject*)0,InputArguments) << "RooClassFactory::makeClass: ERROR: a class name must be given" << endl ;
423  return kTRUE ;
424  }
425 
426  if ((!realArgNames || !*realArgNames) && (!catArgNames || !*catArgNames)) {
427  oocoutE((TObject*)0,InputArguments) << "RooClassFactory::makeClass: ERROR: A list of input argument names must be given" << endl ;
428  return kTRUE ;
429  }
430 
431  if (intExpression && !hasAnaInt) {
432  oocoutE((TObject*)0,InputArguments) << "RooClassFactory::makeClass: ERROR no analytical integration code requestion, but expression for analytical integral provided" << endl ;
433  return kTRUE ;
434  }
435 
436  // Parse comma separated list of argument names into list of strings
437  vector<string> alist ;
438  vector<bool> isCat ;
439 
440  if (realArgNames && *realArgNames) {
441  const size_t bufSize = strlen(realArgNames)+1;
442  char* buf = new char[bufSize] ;
443  strlcpy(buf,realArgNames,bufSize) ;
444  char* token = strtok(buf,",") ;
445  while(token) {
446  alist.push_back(token) ;
447  isCat.push_back(false) ;
448  token = strtok(0,",") ;
449  }
450  delete[] buf ;
451  }
452  if (catArgNames && *catArgNames) {
453  const size_t bufSize = strlen(catArgNames)+1;
454  char* buf = new char[bufSize] ;
455  strlcpy(buf,catArgNames,bufSize) ;
456  char* token = strtok(buf,",") ;
457  while(token) {
458  alist.push_back(token) ;
459  isCat.push_back(true) ;
460  token = strtok(0,",") ;
461  }
462  delete[] buf ;
463  }
464 
465  TString impFileName(className), hdrFileName(className) ;
466  impFileName += ".cxx" ;
467  hdrFileName += ".h" ;
468 
469  TString ifdefName(className) ;
470  ifdefName.ToUpper() ;
471 
472  ofstream hf(hdrFileName) ;
473  hf << "/*****************************************************************************" << endl
474  << " * Project: RooFit *" << endl
475  << " * *" << endl
476  << " * This code was autogenerated by RooClassFactory * " << endl
477  << " *****************************************************************************/" << endl
478  << endl
479  << "#ifndef " << ifdefName << endl
480  << "#define " << ifdefName << endl
481  << "" << endl
482  << "#include \"" << baseName << ".h\"" << endl
483  << "#include \"RooRealProxy.h\"" << endl
484  << "#include \"RooCategoryProxy.h\"" << endl
485  << "#include \"RooAbsReal.h\"" << endl
486  << "#include \"RooAbsCategory.h\"" << endl
487  << " " << endl
488  << "class " << className << " : public " << baseName << " {" << endl
489  << "public:" << endl
490  << " " << className << "() {} ; " << endl
491  << " " << className << "(const char *name, const char *title," << endl ;
492 
493  // Insert list of input arguments
494  unsigned int i ;
495  for (i=0 ; i<alist.size() ; i++) {
496  if (!isCat[i]) {
497  hf << " RooAbsReal& _" ;
498  } else {
499  hf << " RooAbsCategory& _" ;
500  }
501  hf << alist[i] ;
502  if (i==alist.size()-1) {
503  hf << ");" << endl ;
504  } else {
505  hf << "," << endl ;
506  }
507  }
508 
509  hf << " " << className << "(const " << className << "& other, const char* name=0) ;" << endl
510  << " virtual TObject* clone(const char* newname) const { return new " << className << "(*this,newname); }" << endl
511  << " inline virtual ~" << className << "() { }" << endl
512  << endl ;
513 
514  if (hasAnaInt) {
515  hf << " Int_t getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* rangeName=0) const ;" << endl
516  << " Double_t analyticalIntegral(Int_t code, const char* rangeName=0) const ;" << endl
517  << "" << endl ;
518  }
519 
520  if (hasIntGen) {
521  hf << " Int_t getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t staticInitOK=kTRUE) const;" << endl
522  << " void initGenerator(Int_t code) {} ; // optional pre-generation initialization" << endl
523  << " void generateEvent(Int_t code);" << endl
524  << endl ;
525  }
526 
527  hf << "protected:" << endl
528  << "" << endl ;
529 
530  // Insert list of input arguments
531  for (i=0 ; i<alist.size() ; i++) {
532  if (!isCat[i]) {
533  hf << " RooRealProxy " << alist[i] << " ;" << endl ;
534  } else {
535  hf << " RooCategoryProxy " << alist[i] << " ;" << endl ;
536  }
537  }
538 
539  hf << " " << endl
540  << " Double_t evaluate() const ;" << endl
541  << "" << endl
542  << "private:" << endl
543  << "" << endl
544  << " ClassDef(" << className << ",1) // Your description goes here..." << endl
545  << "};" << endl
546  << " " << endl
547  << "#endif" << endl ;
548 
549 
550  ofstream cf(impFileName) ;
551 
552  cf << "/***************************************************************************** " << endl
553  << " * Project: RooFit * " << endl
554  << " * * " << endl
555  << " * This code was autogenerated by RooClassFactory * " << endl
556  << " *****************************************************************************/ " << endl
557  << endl
558  << "// Your description goes here... " << endl
559  << endl
560 
561  << "#include \"Riostream.h\" " << endl
562  << endl
563 
564  << "#include \"" << className << ".h\" " << endl
565  << "#include \"RooAbsReal.h\" " << endl
566  << "#include \"RooAbsCategory.h\" " << endl
567  << "#include <math.h> " << endl
568  << "#include \"TMath.h\" " << endl
569  << endl
570 
571  << "ClassImp(" << className << "); " << endl
572  << endl
573 
574  << " " << className << "::" << className << "(const char *name, const char *title, " << endl ;
575 
576  // Insert list of proxy constructors
577  for (i=0 ; i<alist.size() ; i++) {
578  if (!isCat[i]) {
579  cf << " RooAbsReal& _" << alist[i] ;
580  } else {
581  cf << " RooAbsCategory& _" << alist[i] ;
582  }
583  if (i<alist.size()-1) {
584  cf << "," ;
585  } else {
586  cf << ") :" ;
587  }
588  cf << endl ;
589  }
590 
591  // Insert base class constructor
592  cf << " " << baseName << "(name,title), " << endl ;
593 
594  // Insert list of proxy constructors
595  for (i=0 ; i<alist.size() ; i++) {
596  cf << " " << alist[i] << "(\"" << alist[i] << "\",\"" << alist[i] << "\",this,_" << alist[i] << ")" ;
597  if (i<alist.size()-1) {
598  cf << "," ;
599  }
600  cf << endl ;
601  }
602 
603  cf << " { " << endl
604  << " } " << endl
605  << endl
606  << endl
607 
608  << " " << className << "::" << className << "(const " << className << "& other, const char* name) : " << endl
609  << " " << baseName << "(other,name), " << endl ;
610 
611  for (i=0 ; i<alist.size() ; i++) {
612  cf << " " << alist[i] << "(\"" << alist[i] << "\",this,other." << alist[i] << ")" ;
613  if (i<alist.size()-1) {
614  cf << "," ;
615  }
616  cf << endl ;
617  }
618 
619  cf << " { " << endl
620  << " } " << endl
621  << endl
622  << endl
623  << endl
624 
625  << " Double_t " << className << "::evaluate() const " << endl
626  << " { " << endl
627  << " // ENTER EXPRESSION IN TERMS OF VARIABLE ARGUMENTS HERE " << endl
628  << " return " << expression << " ; " << endl
629  << " } " << endl
630  << endl
631  << endl
632  << endl ;
633 
634  if (hasAnaInt) {
635 
636  vector<string> intObs ;
637  vector<string> intExpr ;
638  // Parse analytical integration expression if provided
639  // Expected form is observable:expression,observable,observable:expression;[...]
640  if (intExpression && *intExpression) {
641  const size_t bufSize = strlen(intExpression)+1;
642  char* buf = new char[bufSize] ;
643  strlcpy(buf,intExpression,bufSize) ;
644  char* ptr = strtok(buf,":") ;
645  while(ptr) {
646  intObs.push_back(ptr) ;
647  intExpr.push_back(strtok(0,";")) ;
648  ptr = strtok(0,":") ;
649  }
650  delete[] buf ;
651  }
652 
653  cf << " Int_t " << className << "::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /*rangeName*/) const " << endl
654  << " { " << endl
655  << " // LIST HERE OVER WHICH VARIABLES ANALYTICAL INTEGRATION IS SUPPORTED, " << endl
656  << " // ASSIGN A NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS " << endl
657  << " // THE EXAMPLE BELOW ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X" << endl
658  << " // YOU CAN ALSO IMPLEMENT MORE THAN ONE ANALYTICAL INTEGRAL BY REPEATING THE matchArgs " << endl
659  << " // EXPRESSION MULTIPLE TIMES" << endl
660  << endl ;
661 
662  if (intObs.size()>0) {
663  for (UInt_t ii=0 ; ii<intObs.size() ; ii++) {
664  cf << " if (matchArgs(allVars,analVars," << intObs[ii] << ")) return " << ii+1 << " ; " << endl ;
665  }
666  } else {
667  cf << " // if (matchArgs(allVars,analVars,x)) return 1 ; " << endl ;
668  }
669 
670  cf << " return 0 ; " << endl
671  << " } " << endl
672  << endl
673  << endl
674  << endl
675 
676  << " Double_t " << className << "::analyticalIntegral(Int_t code, const char* rangeName) const " << endl
677  << " { " << endl
678  << " // RETURN ANALYTICAL INTEGRAL DEFINED BY RETURN CODE ASSIGNED BY getAnalyticalIntegral" << endl
679  << " // THE MEMBER FUNCTION x.min(rangeName) AND x.max(rangeName) WILL RETURN THE INTEGRATION" << endl
680  << " // BOUNDARIES FOR EACH OBSERVABLE x" << endl
681  << endl ;
682 
683  if (intObs.size()>0) {
684  for (UInt_t ii=0 ; ii<intObs.size() ; ii++) {
685  cf << " if (code==" << ii+1 << ") { return (" << intExpr[ii] << ") ; } " << endl ;
686  }
687  } else {
688  cf << " // assert(code==1) ; " << endl
689  << " // return (x.max(rangeName)-x.min(rangeName)) ; " << endl ;
690  }
691 
692  cf << " return 0 ; " << endl
693  << " } " << endl
694  << endl
695  << endl
696  << endl ;
697  }
698 
699  if (hasIntGen) {
700  cf << " Int_t " << className << "::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t /*staticInitOK*/) const " << endl
701  << " { " << endl
702  << " // LIST HERE OVER WHICH VARIABLES INTERNAL GENERATION IS SUPPORTED, " << endl
703  << " // ASSIGN A NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS " << endl
704  << " // THE EXAMPLE BELOW ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X" << endl
705  << " // YOU CAN ALSO IMPLEMENT MORE THAN ONE GENERATOR CONFIGURATION BY REPEATING THE matchArgs " << endl
706  << " // EXPRESSION MULTIPLE TIMES. IF THE FLAG staticInitOK IS TRUE THEN IT IS SAFE TO PRECALCULATE " << endl
707  << " // INTERMEDIATE QUANTITIES IN initGenerator(), IF IT IS NOT SET THEN YOU SHOULD NOT ADVERTISE" << endl
708  << " // ANY GENERATOR METHOD THAT RELIES ON PRECALCULATIONS IN initGenerator()" << endl
709  << endl
710  << " // if (matchArgs(directVars,generateVars,x)) return 1 ; " << endl
711  << " return 0 ; " << endl
712  << " } " << endl
713  << endl
714  << endl
715  << endl
716 
717  << " void " << className << "::generateEvent(Int_t code) " << endl
718  << " { " << endl
719  << " // GENERATE SET OF OBSERVABLES DEFINED BY RETURN CODE ASSIGNED BY getGenerator()" << endl
720  << " // RETURN THE GENERATED VALUES BY ASSIGNING THEM TO THE PROXY DATA MEMBERS THAT" << endl
721  << " // REPRESENT THE CHOSEN OBSERVABLES" << endl
722  << endl
723  << " // assert(code==1) ; " << endl
724  << " // x = 0 ; " << endl
725  << " return; " << endl
726  << " } " << endl
727  << endl
728  << endl
729  << endl ;
730  }
731 
732 
733  return kFALSE ;
734 }
735 
736 ////////////////////////////////////////////////////////////////////////////////
737 
738 std::string RooClassFactory::ClassFacIFace::create(RooFactoryWSTool& ft, const char* typeName, const char* instanceName, std::vector<std::string> args)
739 {
740  static int classCounter = 0 ;
741 
742  string tn(typeName) ;
743  if (tn=="CEXPR" || tn=="cexpr") {
744 
745  if (args.size()<2) {
746  throw string(Form("RooClassFactory::ClassFacIFace::create() ERROR: CEXPR requires at least 2 arguments (expr,var,...), but only %u args found",
747  (UInt_t)args.size())) ;
748  }
749 
750  RooAbsArg* ret ;
751  // Strip quotation marks from expression string
752  char expr[1024] ;
753  strncpy(expr,args[0].c_str()+1,args[0].size()-2) ;
754  expr[args[0].size()-2]=0 ;
755 
756 
757  RooArgList varList ;
758 
759  try {
760  if (args.size()==2) {
761  // Interpret 2nd arg as list
762  varList.add(ft.asLIST(args[1].c_str())) ;
763  } else {
764  for (unsigned int i=1 ; i<args.size() ; i++) {
765  varList.add(ft.asARG(args[i].c_str())) ;
766  }
767  }
768  } catch (const string &err) {
769  throw string(Form("RooClassFactory::ClassFacIFace::create() ERROR: %s",err.c_str())) ;
770  }
771 
772  string className ;
773  while(true) {
774  className = Form("RooCFAuto%03d%s%s",classCounter,(tn=="CEXPR")?"Pdf":"Func",ft.autoClassNamePostFix()) ;
775  TClass* tc = TClass::GetClass(className.c_str(),kTRUE,kTRUE) ;
776  classCounter++ ;
777  if (!tc) {
778  break ;
779  }
780  }
781 
782  if (tn=="CEXPR") {
783  ret = makePdfInstance(className.c_str(),instanceName,expr,varList) ;
784  } else {
785  ret = makeFunctionInstance(className.c_str(),instanceName,expr,varList) ;
786  }
787  if (!ret) {
788  throw string(Form("RooClassFactory::ClassFacIFace::create() ERROR creating %s %s with RooClassFactory",((tn=="CEXPR")?"pdf":"function"),instanceName)) ;
789  }
790 
791  // Import object
792  ft.ws().import(*ret,RooFit::Silence()) ;
793 
794  // Import class code as well
795  ft.ws().importClassCode(ret->IsA()) ;
796 
797 
798  } else {
799 
800  throw string(Form("RooClassFactory::ClassFacIFace::create() ERROR: Unknown meta-type %s requested",typeName)) ;
801 
802  }
803  return string(instanceName) ;
804 }