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" << std::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" << std::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 << std::endl;
460 return true;
461 }
462
463 // Parse comma separated list of argument names into list of strings
464 vector<string> alist;
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 << ");" << std::endl ;
510 } else {
511 hf << "," << std::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 << "" << std::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] << " ;" << std::endl ;
540 } else {
541 hf << " RooCategoryProxy " << alist[i] << " ;" << std::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 << ";" << std::endl
584 << "}\n"
585 << std::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
609
610CLASS_NAME::CLASS_NAME(const char *name, const char *title,
611)";
612
613 // Insert list of proxy constructors
614 for (std::size_t i=0 ; i<alist.size() ; i++) {
615 if (!isCat[i]) {
616 cf << " RooAbsReal& _" << alist[i] ;
617 } else {
618 cf << " RooAbsCategory& _" << alist[i] ;
619 }
620 if (i<alist.size()-1) {
621 cf << "," ;
622 } else {
623 cf << ")" ;
624 }
625 cf << std::endl ;
626 }
627
628 // Insert base class constructor
629 cf << " : BASE_NAME(name,title)," << std::endl ;
630
631 // Insert list of proxy constructors
632 for (std::size_t i=0 ; i<alist.size() ; i++) {
633 cf << " " << alist[i] << "(\"" << alist[i] << "\",\"" << alist[i] << "\",this,_" << alist[i] << ")" ;
634 if (i<alist.size()-1) {
635 cf << "," ;
636 }
637 cf << std::endl ;
638 }
639
640 cf << "{" << std::endl
641 << "}" << std::endl
642 << std::endl
643
644 << "CLASS_NAME::CLASS_NAME(CLASS_NAME const &other, const char *name)" << std::endl
645 << " : BASE_NAME(other,name)," << std::endl ;
646
647 for (std::size_t i=0 ; i<alist.size() ; i++) {
648 cf << " " << alist[i] << "(\"" << alist[i] << "\",this,other." << alist[i] << ")" ;
649 if (i<alist.size()-1) {
650 cf << "," ;
651 }
652 cf << std::endl ;
653 }
654
655 cf << "{\n"
656 << "}\n"
657 << std::endl
658 << "\n"
659 << "double CLASS_NAME::evaluate() const " << std::endl
660 << "{\n"
661 << " return CLASS_NAME_evaluate(" << listVars(alist) << ");" << std::endl
662 << "}\n"
663 << "\n"
664 << "void CLASS_NAME::doEval(RooFit::EvalContext &ctx) const" << std::endl
665 << "{\n"
666 << declareVarSpans(alist)
667 << "\n"
668 << " std::size_t n = ctx.output().size();\n"
669 << " for (std::size_t i = 0; i < n; ++i) {\n"
670 << " ctx.output()[i] = CLASS_NAME_evaluate(" << getFromVarSpans(alist) << ");\n"
671 << " }\n"
672 << "}\n";
673
674 {
675 std::stringstream varsGetters;
676 for (std::size_t i = 0; i < alist.size(); ++i) {
677 varsGetters << "arg." << alist[i];
678 if (i < alist.size() - 1) {
679 varsGetters << ", ";
680 }
681 }
682
683 cf << "void RooFit::Experimental::codegenImpl(CLASS_NAME &arg, RooFit::Experimental::CodegenContext &ctx)\n"
684 << "{\n"
685 << " ctx.addResult(&arg, ctx.buildCall(\"CLASS_NAME_evaluate\", " << varsGetters.str() << "));\n"
686 <<"}\n";
687 }
688
689 if (hasAnaInt) {
690
693 // Parse analytical integration expression if provided
694 // Expected form is observable:expression,observable,observable:expression;[...]
695 if (!intExpression.empty()) {
696 const std::size_t bufSize = intExpression.size()+1;
697 std::vector<char> buf(bufSize);
698 strlcpy(buf.data(),intExpression.c_str(),bufSize) ;
699 char* ptr = strtok(buf.data(),":") ;
700 while(ptr) {
701 intObs.push_back(ptr) ;
702 intExpr.push_back(strtok(nullptr,";")) ;
703 ptr = strtok(nullptr,":") ;
704 }
705 }
706
707 cf << R"(
708int CLASS_NAME::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char */*rangeName*/) const
709{
710 // Support also using the imaginary unit
711 using namespace std::complex_literals;
712 // To be able to also comile C code, we define a variable that behaves like the "I" macro from C.
713 constexpr auto I = 1i;
714
715 // LIST HERE OVER WHICH VARIABLES ANALYTICAL INTEGRATION IS SUPPORTED,
716 // ASSIGN A NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE
717 // BELOW ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X YOU CAN ALSO
718 // IMPLEMENT MORE THAN ONE ANALYTICAL INTEGRAL BY REPEATING THE matchArgs
719 // EXPRESSION MULTIPLE TIMES.
720)";
721
722 if (!intObs.empty()) {
723 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
724 cf << " if (matchArgs(allVars,analVars," << intObs[ii] << ")) return " << ii+1 << " ; " << std::endl ;
725 }
726 } else {
727 cf << " // if (matchArgs(allVars,analVars,x)) return 1 ; " << std::endl ;
728 }
729
730 cf << " return 0 ; " << std::endl
731 << "} " << std::endl
732 << std::endl
733 << std::endl
734
735 << R"(double CLASS_NAME::analyticalIntegral(int code, const char *rangeName) const
736{
737 // RETURN ANALYTICAL INTEGRAL DEFINED BY RETURN CODE ASSIGNED BY
738 // getAnalyticalIntegral(). THE MEMBER FUNCTION x.min(rangeName) AND
739 // x.max(rangeName) WILL RETURN THE INTEGRATION BOUNDARIES FOR EACH
740 // OBSERVABLE x.
741)";
742
743 if (!intObs.empty()) {
744 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
745 cf << " if (code==" << ii+1 << ") { return (" << intExpr[ii] << ") ; } " << std::endl ;
746 }
747 } else {
748 cf << " // assert(code==1) ; " << std::endl
749 << " // return (x.max(rangeName)-x.min(rangeName)) ; " << std::endl ;
750 }
751
752 cf << " return 0 ; " << std::endl
753 << "} " << std::endl;
754 }
755
756 if (hasIntGen) {
757 cf << R"(
758int CLASS_NAME::getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool /*staticInitOK*/) const
759{
760 // LIST HERE OVER WHICH VARIABLES INTERNAL GENERATION IS SUPPORTED, ASSIGN A
761 // NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE BELOW
762 // ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X. YOU CAN ALSO IMPLEMENT
763 // MORE THAN ONE GENERATOR CONFIGURATION BY REPEATING THE matchArgs
764 // EXPRESSION MULTIPLE TIMES. IF THE FLAG staticInitOK IS TRUE, THEN IT IS
765 // SAFE TO PRECALCULATE INTERMEDIATE QUANTITIES IN initGenerator(), IF IT IS
766 // NOT SET THEN YOU SHOULD NOT ADVERTISE ANY GENERATOR METHOD THAT RELIES ON
767 // PRECALCULATIONS IN initGenerator().
768
769 // if (matchArgs(directVars,generateVars,x)) return 1;
770 return 0;
771}
772
773void CLASS_NAME::generateEvent(int code)
774{
775 // GENERATE SET OF OBSERVABLES DEFINED BY RETURN CODE ASSIGNED BY
776 // getGenerator(). RETURN THE GENERATED VALUES BY ASSIGNING THEM TO THE
777 // PROXY DATA MEMBERS THAT REPRESENT THE CHOSEN OBSERVABLES.
778
779 // assert(code==1);
780 // x = 0;
781 return;
782}
783)";
784
785 }
786 // clang-format on
787
788 std::ofstream ohf(className + ".h");
789 std::ofstream ocf(className + ".cxx");
790 std::string headerCode = hf.str();
791 std::string sourceCode = cf.str();
792 RooFit::Detail::replaceAll(headerCode, "CLASS_NAME", className);
793 RooFit::Detail::replaceAll(sourceCode, "CLASS_NAME", className);
796 ohf << headerCode;
797 ocf << sourceCode;
798
799 return false;
800}
801
802namespace {
803
804////////////////////////////////////////////////////////////////////////////////
805
806std::string ClassFacIFace::create(RooFactoryWSTool &ft, const char *typeName, const char *instanceName,
807 std::vector<std::string> args)
808{
809 static int classCounter = 0;
810
811 string tn(typeName);
812
813 if (args.size() < 2) {
814 throw std::runtime_error(Form("RooClassFactory::ClassFacIFace::create() ERROR: CEXPR requires at least 2 "
815 "arguments (expr,var,...), but only %u args found",
816 (UInt_t)args.size()));
817 }
818
819 RooAbsArg *ret;
820 // Strip quotation marks from expression string
821 char expr[1024];
822 strncpy(expr, args[0].c_str() + 1, args[0].size() - 2);
823 expr[args[0].size() - 2] = 0;
824
826
827 if (args.size() == 2) {
828 // Interpret 2nd arg as list
829 varList.add(ft.asLIST(args[1].c_str()));
830 } else {
831 for (unsigned int i = 1; i < args.size(); i++) {
832 varList.add(ft.asARG(args[i].c_str()));
833 }
834 }
835
836 string className;
837 while (true) {
838 className = Form("RooCFAuto%03d%s%s", classCounter, (tn == "CEXPR") ? "Pdf" : "Func", ft.autoClassNamePostFix());
839 TClass *tc = TClass::GetClass(className.c_str(), true, true);
840 classCounter++;
841 if (!tc) {
842 break;
843 }
844 }
845
846 if (tn == "CEXPR") {
848 } else {
850 }
851 if (!ret) {
852 throw std::runtime_error(
853 Form("RooClassFactory::ClassFacIFace::create() ERROR creating %s %s with RooClassFactory",
854 ((tn == "CEXPR") ? "pdf" : "function"), instanceName));
855 }
856
857 // Import object
858 ft.ws().import(*ret, RooFit::Silence());
859
860 // Import class code as well
861 ft.ws().importClassCode(ret->IsA());
862
863 return string(instanceName);
864}
865
866} // 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)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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
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:77
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.
Implementation detail of the RooWorkspace.
static void registerSpecial(const char *typeName, RooFactoryWSTool::IFace *iface)
Register foreign special objects in factory.
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:3069
TLine * line
RooCmdArg Silence(bool flag=true)
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)