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