Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooClassFactory.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/**
18\file RooClassFactory.cxx
19\class RooClassFactory
20\ingroup Roofitcore
21
22Similar to TTree::MakeClass(), generates
23skeleton code for RooAbsPdf and RooAbsReal functions given
24a list of input parameter names. The factory can also compile
25the generated code on the fly, and on request also immediate
26instantiate objects.
27**/
28
29#include "RooClassFactory.h"
30
31#include "TClass.h"
32#include "RooFactoryWSTool.h"
33#include "RooErrorHandler.h"
34#include "RooAbsReal.h"
35#include "RooAbsCategory.h"
36#include "RooArgList.h"
37#include "RooMsgService.h"
38#include "TInterpreter.h"
39#include "RooWorkspace.h"
40#include "RooGlobalFunc.h"
41#include "RooAbsPdf.h"
42#include "RooFitImplHelpers.h"
43
44#include <ROOT/StringUtils.hxx>
45
46#include <strlcpy.h>
47#include <cctype>
48#include <fstream>
49#include <mutex>
50
51using std::endl, std::vector, std::string;
52
53namespace {
54
55class ClassFacIFace : public RooFactoryWSTool::IFace {
56public:
57 std::string
58 create(RooFactoryWSTool &ft, const char *typeName, const char *instanceName, std::vector<std::string> args) override;
59};
60
61static int init();
62
63int dummy = init();
64
65int init()
66{
67 RooFactoryWSTool::IFace *iface = new ClassFacIFace;
70 (void)dummy;
71 return 0;
72}
73
74bool makeAndCompileClass(std::string const &baseClassName, std::string const &name, std::string const &expression,
75 const RooArgList &vars, std::string const &intExpression)
76{
77 // A structure to store the inputs to this function, to check if has been
78 // called already with the same arguments.
79 class ClassInfo {
80 public:
81 ClassInfo(std::string const &baseClassName, std::string const &name, std::string const &expression,
82 const RooArgList &vars, std::string const &intExpression)
83 : _baseClassName{baseClassName}, _name{name}, _expression{expression}, _intExpression{intExpression}
84 {
85 _argNames.reserve(vars.size());
86 _argsAreCategories.reserve(vars.size());
87 for (RooAbsArg *arg : vars) {
88 _argNames.emplace_back(arg->GetName());
89 _argsAreCategories.emplace_back(arg->isCategory());
90 }
91 }
92 bool operator==(const ClassInfo &other) const
93 {
94 return other._baseClassName == _baseClassName && other._name == _name && other._expression == _expression &&
95 other._argNames == _argNames && other._argsAreCategories == _argsAreCategories &&
96 other._intExpression == _intExpression;
97 }
98
99 std::string _baseClassName;
100 std::string _name;
101 std::string _expression;
102 std::vector<std::string> _argNames;
103 std::vector<bool> _argsAreCategories;
104 std::string _intExpression;
105 };
106
107 static std::vector<ClassInfo> infosVec;
108 static std::mutex infosVecMutex; // protects infosVec
109
110 ClassInfo info{baseClassName, name, expression, vars, intExpression};
111
112 // Check if this class was already compiled
113 auto found = std::find_if(infosVec.begin(), infosVec.end(), [&](auto const &elem) { return elem._name == name; });
114 if (found != infosVec.end()) {
115 if (*found == info) {
116 return false;
117 }
118 std::stringstream ss;
119 ss << "RooClassFactory ERROR The type, expressions, or variables for the class \"" << name
120 << "\" are not identical to what you passed last time this class was compiled! This is not allowed.";
121 oocoutE(nullptr, InputArguments) << ss.str() << std::endl;
122 throw std::runtime_error(ss.str());
123 }
124
125 // Making a new compiled class is not thread safe
126 const std::lock_guard<std::mutex> lock(infosVecMutex);
127
128 infosVec.emplace_back(info);
129
130 std::string realArgNames;
131 std::string catArgNames;
132 for (RooAbsArg *arg : vars) {
133 if (dynamic_cast<RooAbsReal *>(arg)) {
134 if (!realArgNames.empty())
135 realArgNames += ",";
136 realArgNames += arg->GetName();
137 } else if (arg->isCategory()) {
138 if (!catArgNames.empty())
139 catArgNames += ",";
140 catArgNames += arg->GetName();
141 } else {
142 oocoutE(nullptr, InputArguments) << "RooClassFactory ERROR input argument " << arg->GetName()
143 << " is neither RooAbsReal nor RooAbsCategory and is ignored" << endl;
144 }
145 }
146
147 bool ret = RooClassFactory::makeClass(baseClassName, name, realArgNames, catArgNames, expression,
148 !intExpression.empty(), false, intExpression);
149 if (ret) {
150 return ret;
151 }
152
154 gInterpreter->ProcessLineSynch((".L " + name + ".cxx+").c_str(), &ecode);
155 return (ecode != TInterpreter::kNoError);
156}
157
158RooAbsReal *makeClassInstance(std::string const &baseClassName, std::string const &className, std::string const &name,
159 std::string const &expression, const RooArgList &vars, std::string const &intExpression)
160{
161 // Use class factory to compile and link specialized function
162 bool error = makeAndCompileClass(baseClassName, className, expression, vars, intExpression);
163
164 // Check that class was created OK
165 if (error) {
167 }
168
169 // Create interpreter line that instantiates specialized object
170 std::string line = std::string("new ") + className + "(\"" + name + "\",\"" + name + "\"";
171
172 // Make list of pointer values (represented in hex ascii) to be passed to cint
173 // Note that the order of passing arguments must match the convention in which
174 // the class code is generated: first all reals, then all categories
175
176 std::string argList;
177 // First pass the RooAbsReal arguments in the list order
178 for (RooAbsArg *var : vars) {
179 if (dynamic_cast<RooAbsReal *>(var)) {
180 argList += Form(",*reinterpret_cast<RooAbsReal*>(0x%zx)", reinterpret_cast<std::size_t>(var));
181 }
182 }
183 // Next pass the RooAbsCategory arguments in the list order
184 for (RooAbsArg *var : vars) {
185 if (var->isCategory()) {
186 argList += Form(",*reinterpret_cast<RooAbsCategory*>(0x%zx)", reinterpret_cast<std::size_t>(var));
187 }
188 }
189
190 line += argList + ") ;";
191
192 // Let interpreter instantiate specialized formula
193 return reinterpret_cast<RooAbsReal *>(gInterpreter->ProcessLineSynch(line.c_str()));
194}
195
196} // namespace
197
198////////////////////////////////////////////////////////////////////////////////
199
200bool RooClassFactory::makeAndCompilePdf(std::string const &name, std::string const &expression, const RooArgList &vars,
201 std::string const &intExpression)
202{
203 return makeAndCompileClass("RooAbsPdf", name, expression, vars, intExpression);
204}
205
206////////////////////////////////////////////////////////////////////////////////
207/// Write, compile and load code for a RooAbsReal implementation with
208/// class name 'name', taking all elements of 'vars' as constructor
209/// arguments. The initial value expression is taken to be
210/// 'expression' which can be any one-line C++ expression in terms of
211/// variables that occur in 'vars'. You can add optional expressions
212/// for analytical integrals to be advertised by your class in the
213/// syntax
214/// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
215/// where "<intObsName>" a name of the observable integrated over and
216/// "<CPPAnaIntExpression>" is the C++ expression that calculates that
217/// integral.
218
219bool RooClassFactory::makeAndCompileFunction(std::string const &name, std::string const &expression,
220 const RooArgList &vars, std::string const &intExpression)
221{
222 return makeAndCompileClass("RooAbsReal", name, expression, vars, intExpression);
223}
224
225////////////////////////////////////////////////////////////////////////////////
226/// Write, compile and load code and instantiate object for a
227/// RooAbsReal implementation with class name 'name', taking all
228/// elements of 'vars' as constructor arguments. The initial value
229/// expression is taken to be 'expression' which can be any one-line
230/// C++ expression in terms of variables that occur in 'vars'.
231///
232/// The returned object is an instance of the object you just defined
233/// connected to the variables listed in 'vars'. The name of the
234/// object is 'name', its class name Roo<name>Class.
235///
236/// This function is an effective compiled replacement of RooFormulaVar
237///
238/// You can add optional expressions for analytical integrals to be
239/// advertised by your class in the syntax
240/// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
241/// where "<intObsName>" a name of the observable integrated over and
242/// "<CPPAnaIntExpression>" is the C++ expression that calculates that
243/// integral.
244
245RooAbsReal *RooClassFactory::makeFunctionInstance(std::string const &name, std::string const &expression,
246 const RooArgList &vars, std::string const &intExpression)
247{
248 // Construct unique class name for this function expression
249 std::string tmpName(name);
250 tmpName[0] = toupper(tmpName[0]);
251 string className = "Roo" + tmpName + "Func";
252
253 return makeFunctionInstance(className, name, expression, vars, intExpression);
254}
255
256////////////////////////////////////////////////////////////////////////////////
257/// Write, compile and load code and instantiate object for a
258/// RooAbsReal implementation with class name 'name', taking all
259/// elements of 'vars' as constructor arguments. The initial value
260/// expression is taken to be 'expression' which can be any one-line
261/// C++ expression in terms of variables that occur in 'vars'.
262///
263/// The returned object is an instance of the object you just defined
264/// connected to the variables listed in 'vars'. The name of the
265/// object is 'name', its class name Roo<name>Class.
266///
267/// This function is an effective compiled replacement of RooFormulaVar
268///
269/// You can add optional expressions for analytical integrals to be
270/// advertised by your class in the syntax
271/// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
272/// where "<intObsName>" a name of the observable integrated over and
273/// "<CPPAnaIntExpression>" is the C++ expression that calculates that
274/// integral.
275
276RooAbsReal *RooClassFactory::makeFunctionInstance(std::string const &className, std::string const &name,
277 std::string const &expression, const RooArgList &vars,
278 std::string const &intExpression)
279{
280 return static_cast<RooAbsReal *>(makeClassInstance("RooAbsRal", className, name, expression, vars, intExpression));
281}
282
283////////////////////////////////////////////////////////////////////////////////
284/// Write, compile and load code and instantiate object for a RooAbsPdf
285/// implementation. The difference to makeFunctionInstance() is the base
286/// class of the written class (RooAbsPdf instead of RooAbsReal).
287///
288/// \see RooClassFactory::makeFunctionInstance(const char*, const char*, RooArgList const&, const char*)
289
290RooAbsPdf *RooClassFactory::makePdfInstance(std::string const &name, std::string const &expression,
291 const RooArgList &vars, std::string const &intExpression)
292{
293 // Construct unique class name for this function expression
294 std::string tmpName(name);
295 tmpName[0] = toupper(tmpName[0]);
296 string className = "Roo" + tmpName + "Pdf";
297
298 return makePdfInstance(className, name, expression, vars, intExpression);
299}
300
301////////////////////////////////////////////////////////////////////////////////
302/// Write, compile and load code and instantiate object for a
303/// RooAbsPdf implementation with class name 'name', taking all
304/// elements of 'vars' as constructor arguments. The initial value
305/// expression is taken to be 'expression' which can be any one-line
306/// C++ expression in terms of variables that occur in 'vars'.
307///
308/// The returned object is an instance of the object you just defined
309/// connected to the variables listed in 'vars'. The name of the
310/// object is 'name', its class name Roo<name>Class.
311///
312/// This function is an effective compiled replacement of RooGenericPdf
313///
314/// You can add optional expressions for analytical integrals to be
315/// advertised by your class in the syntax
316/// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
317/// where "<intObsName>" a name of the observable integrated over and
318/// "<CPPAnaIntExpression>" is the C++ expression that calculates that
319/// integral.
320
321RooAbsPdf *RooClassFactory::makePdfInstance(std::string const &className, std::string const &name,
322 std::string const &expression, const RooArgList &vars,
323 std::string const &intExpression)
324{
325 return static_cast<RooAbsPdf *>(makeClassInstance("RooAbsPdf", className, name, expression, vars, intExpression));
326}
327
328////////////////////////////////////////////////////////////////////////////////
329/// Write code for a RooAbsPdf implementation with class name 'name'.
330/// The difference to makePdf() is the base
331/// class of the written class (RooAbsPdf instead of RooAbsReal).
332///
333/// \see RooClassFactory::makePdf(const char*, const char*, std::string const &, const char*, RooArgList const&, bool,
334/// bool, const char*)
335
336bool RooClassFactory::makePdf(std::string const &name, std::string const &argNames, std::string const &catArgNames,
337 std::string const &expression, bool hasAnaInt, bool hasIntGen,
338 std::string const &intExpression)
339{
340 return makeClass("RooAbsPdf", name, argNames, catArgNames, expression, hasAnaInt, hasIntGen, intExpression);
341}
342
343////////////////////////////////////////////////////////////////////////////////
344/// Write code for a RooAbsReal implementation with class name 'name',
345/// taking RooAbsReal arguments with names listed in argNames and
346/// RooAbsCategory arguments with names listed in catArgNames as
347/// constructor arguments (use a comma separated list for multiple
348/// arguments). The initial value expression is taken to be
349/// 'expression' which can be any one-line C++ expression in terms of
350/// variables that occur in 'vars'. Skeleton code for handling of
351/// analytical integrals is added if hasAnaInt is true. You can add
352/// optional expressions for analytical integrals to be advertised by
353/// your class in the syntax
354/// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
355/// where "<intObsName>" a name of the observable integrated over and
356/// "<CPPAnaIntExpression>" is the C++ expression that calculates that
357/// integral.
358
359bool RooClassFactory::makeFunction(std::string const &name, std::string const &argNames, std::string const &catArgNames,
360 std::string const &expression, bool hasAnaInt, std::string const &intExpression)
361{
362 return makeClass("RooAbsReal", name, argNames, catArgNames, expression, hasAnaInt, false, intExpression);
363}
364
365namespace {
366
367std::string listVars(std::vector<std::string> const &alist, std::vector<bool> const &isCat = {})
368{
369 std::stringstream ss;
370 for (std::size_t i = 0; i < alist.size(); ++i) {
371 if (!isCat.empty()) {
372 ss << (isCat[i] ? "int" : "double") << " ";
373 }
374 ss << alist[i];
375 if (i < alist.size() - 1) {
376 ss << ", ";
377 }
378 }
379 return ss.str();
380}
381
382std::string declareVarSpans(std::vector<std::string> const &alist)
383{
384 std::stringstream ss;
385 for (std::size_t i = 0; i < alist.size(); ++i) {
386 ss << " "
387 << "std::span<const double> " << alist[i] << "Span = ctx.at(" << alist[i] << ");\n";
388 }
389 return ss.str();
390}
391
392std::string getFromVarSpans(std::vector<std::string> const &alist)
393{
394 std::stringstream ss;
395 for (std::size_t i = 0; i < alist.size(); ++i) {
396 std::string name = alist[i] + "Span";
397 ss << name << ".size() > 1 ? " << name << "[i] : " << name << "[0]";
398 if (i < alist.size() - 1) {
399 ss << ",\n ";
400 }
401 }
402 return ss.str();
403}
404
405inline bool isSpecial(char c)
406{
407 return c != '_' && !std::isalnum(c);
408}
409
410bool isComplex(std::string const &expression)
411{
412 // Let's figure out if the expression contains the imaginary unit
413
414 for (std::size_t i = 0; i < expression.size(); ++i) {
415 bool leftOkay = (i == 0) || isSpecial(expression[i - 1]);
416 bool rightOkay = (i == expression.size() - 1) || isSpecial(expression[i + 1]);
417 if (expression[i] == 'I' && leftOkay && rightOkay)
418 return true;
419 }
420 return false;
421}
422
423} // namespace
424
425////////////////////////////////////////////////////////////////////////////////
426/// Write code for a 'baseName' implementation with class name 'className',
427/// taking RooAbsReal arguments with names listed in argNames and
428/// RooAbsCategory arguments with names listed in catArgNames as
429/// constructor arguments (use a comma separated list for multiple
430/// arguments). The initial value expression is taken to be
431/// 'expression' which can be any one-line C++ expression in terms of
432/// variables that occur in 'vars'. Skeleton code for handling of
433/// analytical integrals is added if hasAnaInt is true. You can add
434/// optional expressions for analytical integrals to be advertised by
435/// your class in the syntax
436/// "<intObsName>:<CPPAnaIntExpression>;<intObsName,intObsName>:<CPPAnaIntExpression>"
437/// where "<intObsName>" a name of the observable integrated over and
438/// "<CPPAnaIntExpression>" is the C++ expression that calculates that
439/// integral. Skeleton code for internal event generation is added
440/// if hasIntGen is true
441///
442
443bool RooClassFactory::makeClass(std::string const &baseName, std::string const &className,
444 std::string const &realArgNames, std::string const &catArgNames,
445 std::string const &expression, bool hasAnaInt, bool hasIntGen,
446 std::string const &intExpression)
447{
448 // Check that arguments were given
449
450 if (realArgNames.empty() && catArgNames.empty()) {
451 oocoutE(nullptr, InputArguments)
452 << "RooClassFactory::makeClass: ERROR: A list of input argument names must be given" << endl;
453 return true;
454 }
455
456 if (!intExpression.empty() && !hasAnaInt) {
457 oocoutE(nullptr, InputArguments) << "RooClassFactory::makeClass: ERROR no analytical integration code "
458 "requestion, but expression for analytical integral provided"
459 << endl;
460 return true;
461 }
462
463 // Parse comma separated list of argument names into list of strings
464 vector<string> alist;
465 vector<bool> isCat;
466
467 for (auto const &token : ROOT::Split(realArgNames, ",", /*skipEmpyt=*/true)) {
468 alist.push_back(token);
469 isCat.push_back(false);
470 }
471 for (auto const &token : ROOT::Split(catArgNames, ",", /*skipEmpyt=*/true)) {
472 alist.push_back(token);
473 isCat.push_back(true);
474 }
475
476 // clang-format off
477 std::stringstream hf;
478 hf << R"(/*****************************************************************************
479 * Project: RooFit *
480 * *
481 * This code was autogenerated by RooClassFactory *
482 *****************************************************************************/
483
484#ifndef CLASS_NAME_h
485#define CLASS_NAME_h
486
487#include <BASE_NAME.h>
488#include <RooRealProxy.h>
489#include <RooCategoryProxy.h>
490#include <RooAbsReal.h>
491#include <RooAbsCategory.h>
492
493#include <complex>
494
495class CLASS_NAME : public BASE_NAME {
496public:
497 CLASS_NAME() {}
498 CLASS_NAME(const char *name, const char *title,)";
499
500 // Insert list of input arguments
501 for (std::size_t i=0 ; i<alist.size() ; i++) {
502 if (!isCat[i]) {
503 hf << " RooAbsReal& _" ;
504 } else {
505 hf << " RooAbsCategory& _" ;
506 }
507 hf << alist[i] ;
508 if (i==alist.size()-1) {
509 hf << ");" << endl ;
510 } else {
511 hf << "," << endl ;
512 }
513 }
514
515 hf << R"( CLASS_NAME(CLASS_NAME const &other, const char *name=nullptr);
516 TObject* clone(const char *newname) const override { return new CLASS_NAME(*this, newname); }
517)";
518
519 if (hasAnaInt) {
520 hf << R"(
521 int getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char *rangeName=nullptr) const override;
522 double analyticalIntegral(int code, const char *rangeName=nullptr) const override;
523)";
524 }
525
526 if (hasIntGen) {
527 hf << R"(
528 int getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, bool staticInitOK=true) const override;
529 void initGenerator(int code) override {} // optional pre-generation initialization
530 void generateEvent(int code) override;
531)";
532 }
533
534 hf << "" << endl ;
535
536 // Insert list of input arguments
537 for (std::size_t i=0 ; i<alist.size() ; i++) {
538 if (!isCat[i]) {
539 hf << " RooRealProxy " << alist[i] << " ;" << endl ;
540 } else {
541 hf << " RooCategoryProxy " << alist[i] << " ;" << endl ;
542 }
543 }
544
545 hf << R"(
546 double evaluate() const override;
547 void doEval(RooFit::EvalContext &) const override;
548
549private:
550
551 ClassDefOverride(CLASS_NAME, 1) // Your description goes here...
552};
553
554namespace RooFit {
555namespace Experimental {
556
557void codegenImpl(CLASS_NAME &arg, CodegenContext &ctx);
558
559} // namespace Experimental
560} // namespace RooFit
561
562)";
563
564
565 hf << "inline double CLASS_NAME_evaluate(" << listVars(alist, isCat) << ")";
566 hf << R"(
567{)";
568
569 // When Clad is supporting std::complex, we might drop this check and always write the definition of I.
570 if (isComplex(expression)) {
571 hf << R"(
572 // Support also using the imaginary unit
573 using namespace std::complex_literals;
574 // To be able to also comile C code, we define a variable that behaves like the "I" macro from C.
575 constexpr auto I = 1i;
576)";
577 }
578
579 hf << R"(
580 // ENTER EXPRESSION IN TERMS OF VARIABLE ARGUMENTS HERE
581
582)"
583 << " return " << expression << ";" << endl
584 << "}\n"
585 << endl;
586
587 hf << "\n#endif // CLASS_NAME_h";
588
589 std::stringstream cf;
590
591 cf << R"(/*****************************************************************************
592 * Project: RooFit *
593 * *
594 * This code was autogenerated by RooClassFactory *
595 *****************************************************************************/
596
597// Your description goes here...
598
599#include "CLASS_NAME.h"
600
601#include <RooAbsReal.h>
602#include <RooAbsCategory.h>
603
604#include <Riostream.h>
605#include <TMath.h>
606
607#include <cmath>
608
609ClassImp(CLASS_NAME);
610
611CLASS_NAME::CLASS_NAME(const char *name, const char *title,
612)";
613
614 // Insert list of proxy constructors
615 for (std::size_t i=0 ; i<alist.size() ; i++) {
616 if (!isCat[i]) {
617 cf << " RooAbsReal& _" << alist[i] ;
618 } else {
619 cf << " RooAbsCategory& _" << alist[i] ;
620 }
621 if (i<alist.size()-1) {
622 cf << "," ;
623 } else {
624 cf << ")" ;
625 }
626 cf << endl ;
627 }
628
629 // Insert base class constructor
630 cf << " : BASE_NAME(name,title)," << endl ;
631
632 // Insert list of proxy constructors
633 for (std::size_t i=0 ; i<alist.size() ; i++) {
634 cf << " " << alist[i] << "(\"" << alist[i] << "\",\"" << alist[i] << "\",this,_" << alist[i] << ")" ;
635 if (i<alist.size()-1) {
636 cf << "," ;
637 }
638 cf << endl ;
639 }
640
641 cf << "{" << endl
642 << "}" << endl
643 << endl
644
645 << "CLASS_NAME::CLASS_NAME(CLASS_NAME const &other, const char *name)" << endl
646 << " : BASE_NAME(other,name)," << endl ;
647
648 for (std::size_t i=0 ; i<alist.size() ; i++) {
649 cf << " " << alist[i] << "(\"" << alist[i] << "\",this,other." << alist[i] << ")" ;
650 if (i<alist.size()-1) {
651 cf << "," ;
652 }
653 cf << endl ;
654 }
655
656 cf << "{\n"
657 << "}\n"
658 << endl
659 << "\n"
660 << "double CLASS_NAME::evaluate() const " << endl
661 << "{\n"
662 << " return CLASS_NAME_evaluate(" << listVars(alist) << ");" << endl
663 << "}\n"
664 << "\n"
665 << "void CLASS_NAME::doEval(RooFit::EvalContext &ctx) const" << endl
666 << "{\n"
667 << declareVarSpans(alist)
668 << "\n"
669 << " std::size_t n = ctx.output().size();\n"
670 << " for (std::size_t i = 0; i < n; ++i) {\n"
671 << " ctx.output()[i] = CLASS_NAME_evaluate(" << getFromVarSpans(alist) << ");\n"
672 << " }\n"
673 << "}\n";
674
675 {
676 std::stringstream varsGetters;
677 for (std::size_t i = 0; i < alist.size(); ++i) {
678 varsGetters << "arg." << alist[i];
679 if (i < alist.size() - 1) {
680 varsGetters << ", ";
681 }
682 }
683
684 cf << "void RooFit::Experimental::codegenImpl(CLASS_NAME &arg, RooFit::Experimental::CodegenContext &ctx)\n"
685 << "{\n"
686 << " ctx.addResult(&arg, ctx.buildCall(\"CLASS_NAME_evaluate\", " << varsGetters.str() << "));\n"
687 <<"}\n";
688 }
689
690 if (hasAnaInt) {
691
692 vector<string> intObs ;
693 vector<string> intExpr ;
694 // Parse analytical integration expression if provided
695 // Expected form is observable:expression,observable,observable:expression;[...]
696 if (!intExpression.empty()) {
697 const std::size_t bufSize = intExpression.size()+1;
698 std::vector<char> buf(bufSize);
699 strlcpy(buf.data(),intExpression.c_str(),bufSize) ;
700 char* ptr = strtok(buf.data(),":") ;
701 while(ptr) {
702 intObs.push_back(ptr) ;
703 intExpr.push_back(strtok(nullptr,";")) ;
704 ptr = strtok(nullptr,":") ;
705 }
706 }
707
708 cf << R"(
709int CLASS_NAME::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char */*rangeName*/) const
710{
711 // Support also using the imaginary unit
712 using namespace std::complex_literals;
713 // To be able to also comile C code, we define a variable that behaves like the "I" macro from C.
714 constexpr auto I = 1i;
715
716 // LIST HERE OVER WHICH VARIABLES ANALYTICAL INTEGRATION IS SUPPORTED,
717 // ASSIGN A NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE
718 // BELOW ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X YOU CAN ALSO
719 // IMPLEMENT MORE THAN ONE ANALYTICAL INTEGRAL BY REPEATING THE matchArgs
720 // EXPRESSION MULTIPLE TIMES.
721)";
722
723 if (!intObs.empty()) {
724 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
725 cf << " if (matchArgs(allVars,analVars," << intObs[ii] << ")) return " << ii+1 << " ; " << endl ;
726 }
727 } else {
728 cf << " // if (matchArgs(allVars,analVars,x)) return 1 ; " << endl ;
729 }
730
731 cf << " return 0 ; " << endl
732 << "} " << endl
733 << endl
734 << endl
735
736 << R"(double CLASS_NAME::analyticalIntegral(int code, const char *rangeName) const
737{
738 // RETURN ANALYTICAL INTEGRAL DEFINED BY RETURN CODE ASSIGNED BY
739 // getAnalyticalIntegral(). THE MEMBER FUNCTION x.min(rangeName) AND
740 // x.max(rangeName) WILL RETURN THE INTEGRATION BOUNDARIES FOR EACH
741 // OBSERVABLE x.
742)";
743
744 if (!intObs.empty()) {
745 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
746 cf << " if (code==" << ii+1 << ") { return (" << intExpr[ii] << ") ; } " << endl ;
747 }
748 } else {
749 cf << " // assert(code==1) ; " << endl
750 << " // return (x.max(rangeName)-x.min(rangeName)) ; " << endl ;
751 }
752
753 cf << " return 0 ; " << endl
754 << "} " << endl;
755 }
756
757 if (hasIntGen) {
758 cf << R"(
759int CLASS_NAME::getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool /*staticInitOK*/) const
760{
761 // LIST HERE OVER WHICH VARIABLES INTERNAL GENERATION IS SUPPORTED, ASSIGN A
762 // NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE BELOW
763 // ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X. YOU CAN ALSO IMPLEMENT
764 // MORE THAN ONE GENERATOR CONFIGURATION BY REPEATING THE matchArgs
765 // EXPRESSION MULTIPLE TIMES. IF THE FLAG staticInitOK IS TRUE, THEN IT IS
766 // SAFE TO PRECALCULATE INTERMEDIATE QUANTITIES IN initGenerator(), IF IT IS
767 // NOT SET THEN YOU SHOULD NOT ADVERTISE ANY GENERATOR METHOD THAT RELIES ON
768 // PRECALCULATIONS IN initGenerator().
769
770 // if (matchArgs(directVars,generateVars,x)) return 1;
771 return 0;
772}
773
774void CLASS_NAME::generateEvent(int code)
775{
776 // GENERATE SET OF OBSERVABLES DEFINED BY RETURN CODE ASSIGNED BY
777 // getGenerator(). RETURN THE GENERATED VALUES BY ASSIGNING THEM TO THE
778 // PROXY DATA MEMBERS THAT REPRESENT THE CHOSEN OBSERVABLES.
779
780 // assert(code==1);
781 // x = 0;
782 return;
783}
784)";
785
786 }
787 // clang-format on
788
789 std::ofstream ohf(className + ".h");
790 std::ofstream ocf(className + ".cxx");
791 std::string headerCode = hf.str();
792 std::string sourceCode = cf.str();
793 RooFit::Detail::replaceAll(headerCode, "CLASS_NAME", className);
794 RooFit::Detail::replaceAll(sourceCode, "CLASS_NAME", className);
795 RooFit::Detail::replaceAll(headerCode, "BASE_NAME", baseName);
796 RooFit::Detail::replaceAll(sourceCode, "BASE_NAME", baseName);
797 ohf << headerCode;
798 ocf << sourceCode;
799
800 return false;
801}
802
803namespace {
804
805////////////////////////////////////////////////////////////////////////////////
806
807std::string ClassFacIFace::create(RooFactoryWSTool &ft, const char *typeName, const char *instanceName,
808 std::vector<std::string> args)
809{
810 static int classCounter = 0;
811
812 string tn(typeName);
813
814 if (args.size() < 2) {
815 throw std::runtime_error(Form("RooClassFactory::ClassFacIFace::create() ERROR: CEXPR requires at least 2 "
816 "arguments (expr,var,...), but only %u args found",
817 (UInt_t)args.size()));
818 }
819
820 RooAbsArg *ret;
821 // Strip quotation marks from expression string
822 char expr[1024];
823 strncpy(expr, args[0].c_str() + 1, args[0].size() - 2);
824 expr[args[0].size() - 2] = 0;
825
826 RooArgList varList;
827
828 if (args.size() == 2) {
829 // Interpret 2nd arg as list
830 varList.add(ft.asLIST(args[1].c_str()));
831 } else {
832 for (unsigned int i = 1; i < args.size(); i++) {
833 varList.add(ft.asARG(args[i].c_str()));
834 }
835 }
836
837 string className;
838 while (true) {
839 className = Form("RooCFAuto%03d%s%s", classCounter, (tn == "CEXPR") ? "Pdf" : "Func", ft.autoClassNamePostFix());
840 TClass *tc = TClass::GetClass(className.c_str(), true, true);
841 classCounter++;
842 if (!tc) {
843 break;
844 }
845 }
846
847 if (tn == "CEXPR") {
848 ret = RooClassFactory::makePdfInstance(className, instanceName, expr, varList);
849 } else {
850 ret = RooClassFactory::makeFunctionInstance(className, instanceName, expr, varList);
851 }
852 if (!ret) {
853 throw std::runtime_error(
854 Form("RooClassFactory::ClassFacIFace::create() ERROR creating %s %s with RooClassFactory",
855 ((tn == "CEXPR") ? "pdf" : "function"), instanceName));
856 }
857
858 // Import object
859 ft.ws().import(*ret, RooFit::Silence());
860
861 // Import class code as well
862 ft.ws().importClassCode(ret->IsA());
863
864 return string(instanceName);
865}
866
867} // namespace
#define c(i)
Definition RSha256.hxx:101
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define oocoutE(o, a)
Bool_t operator==(const TDatime &d1, const TDatime &d2)
Definition TDatime.h:102
char name[80]
Definition TGX11.cxx:110
#define gInterpreter
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:59
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
static bool makePdf(std::string const &name, std::string const &realArgNames="", std::string const &catArgNames="", std::string const &expression="1.0", bool hasAnaInt=false, bool hasIntGen=false, std::string const &intExpression="")
Write code for a RooAbsPdf implementation with class name 'name'.
static bool makeAndCompilePdf(std::string const &name, std::string const &expression, const RooArgList &vars, std::string const &intExpression="")
static RooAbsReal * makeFunctionInstance(std::string const &className, std::string const &name, std::string const &expression, const RooArgList &vars, std::string const &intExpression="")
Write, compile and load code and instantiate object for a RooAbsReal implementation with class name '...
static bool makeFunction(std::string const &name, std::string const &realArgNames="", std::string const &catArgNames="", std::string const &expression="1.0", bool hasAnaInt=false, std::string const &intExpression="")
Write code for a RooAbsReal implementation with class name 'name', taking RooAbsReal arguments with n...
static RooAbsPdf * makePdfInstance(std::string const &className, std::string const &name, std::string const &expression, const RooArgList &vars, std::string const &intExpression="")
Write, compile and load code and instantiate object for a RooAbsPdf implementation with class name 'n...
static bool makeClass(std::string const &baseName, const std::string &className, std::string const &realArgNames="", std::string const &catArgNames="", std::string const &expression="1.0", bool hasAnaInt=false, bool hasIntGen=false, std::string const &intExpression="")
Write code for a 'baseName' implementation with class name 'className', taking RooAbsReal arguments w...
static bool makeAndCompileFunction(std::string const &name, std::string const &expression, const RooArgList &args, std::string const &intExpression="")
Write, compile and load code for a RooAbsReal implementation with class name 'name',...
static void softAbort()
Soft abort function that interrupts macro execution but doesn't kill ROOT.
virtual std::string create(RooFactoryWSTool &ft, const char *typeName, const char *instanceName, std::vector< std::string > args)=0
Implementation detail of the RooWorkspace.
RooWorkspace & ws()
RooAbsArg & asARG(const char *)
CINT constructor interface, return constructor string argument #idx as RooAbsArg reference found in w...
static void registerSpecial(const char *typeName, RooFactoryWSTool::IFace *iface)
Register foreign special objects in factory.
RooArgList asLIST(const char *)
CINT constructor interface, return constructor string argument #idx as RooArgList of objects found in...
bool importClassCode(const char *pat="*", bool doReplace=false)
Import code of all classes in the workspace that have a class name that matches pattern 'pat' and whi...
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:81
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:3037
TClass * IsA() const override
Definition TNamed.h:58
TLine * line
RooCmdArg Silence(bool flag=true)
void(off) SmallVectorTemplateBase< T
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
void replaceAll(std::string &inOut, std::string_view what, std::string_view with)