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