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