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 namespace std;
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 = dataMap.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 computeBatch(double* output, std::size_t size, RooFit::Detail::DataMap const&) 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::computeBatch(double *output, std::size_t size, RooFit::Detail::DataMap const &dataMap) const " << endl
668 << "{ \n"
669 << declareVarSpans(alist)
670 << "\n"
671 << " for (std::size_t i = 0; i < size; ++i) {\n"
672 << " output[i] = CLASS_NAME_evaluate(" << getFromVarSpans(alist) << ");\n"
673 << " }\n"
674 << "} \n";
675
676cf << "void CLASS_NAME::translate(RooFit::Detail::CodeSquashContext &ctx) const\n"
677<< "{\n"
678<< " ctx.addResult(this, ctx.buildCall(\"CLASS_NAME_evaluate\", " << listVars(alist) << "));\n"
679<<"}\n";
680
681 if (hasAnaInt) {
682
683 vector<string> intObs ;
684 vector<string> intExpr ;
685 // Parse analytical integration expression if provided
686 // Expected form is observable:expression,observable,observable:expression;[...]
687 if (!intExpression.empty()) {
688 const std::size_t bufSize = intExpression.size()+1;
689 std::vector<char> buf(bufSize);
690 strlcpy(buf.data(),intExpression.c_str(),bufSize) ;
691 char* ptr = strtok(buf.data(),":") ;
692 while(ptr) {
693 intObs.push_back(ptr) ;
694 intExpr.push_back(strtok(nullptr,";")) ;
695 ptr = strtok(nullptr,":") ;
696 }
697 }
698
699 cf << R"(
700int CLASS_NAME::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char */*rangeName*/) const
701{
702 // Support also using the imaginary unit
703 using namespace std::complex_literals;
704 // To be able to also comile C code, we define a variable that behaves like the "I" macro from C.
705 constexpr auto I = 1i;
706
707 // LIST HERE OVER WHICH VARIABLES ANALYTICAL INTEGRATION IS SUPPORTED,
708 // ASSIGN A NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE
709 // BELOW ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X YOU CAN ALSO
710 // IMPLEMENT MORE THAN ONE ANALYTICAL INTEGRAL BY REPEATING THE matchArgs
711 // EXPRESSION MULTIPLE TIMES.
712)";
713
714 if (!intObs.empty()) {
715 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
716 cf << " if (matchArgs(allVars,analVars," << intObs[ii] << ")) return " << ii+1 << " ; " << endl ;
717 }
718 } else {
719 cf << " // if (matchArgs(allVars,analVars,x)) return 1 ; " << endl ;
720 }
721
722 cf << " return 0 ; " << endl
723 << "} " << endl
724 << endl
725 << endl
726
727 << R"(double CLASS_NAME::analyticalIntegral(int code, const char *rangeName) const
728{
729 // RETURN ANALYTICAL INTEGRAL DEFINED BY RETURN CODE ASSIGNED BY
730 // getAnalyticalIntegral(). THE MEMBER FUNCTION x.min(rangeName) AND
731 // x.max(rangeName) WILL RETURN THE INTEGRATION BOUNDARIES FOR EACH
732 // OBSERVABLE x.
733)";
734
735 if (!intObs.empty()) {
736 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
737 cf << " if (code==" << ii+1 << ") { return (" << intExpr[ii] << ") ; } " << endl ;
738 }
739 } else {
740 cf << " // assert(code==1) ; " << endl
741 << " // return (x.max(rangeName)-x.min(rangeName)) ; " << endl ;
742 }
743
744 cf << " return 0 ; " << endl
745 << "} " << endl;
746 }
747
748 if (hasIntGen) {
749 cf << R"(
750int CLASS_NAME::getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool /*staticInitOK*/) const
751{
752 // LIST HERE OVER WHICH VARIABLES INTERNAL GENERATION IS SUPPORTED, ASSIGN A
753 // NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE BELOW
754 // ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X. YOU CAN ALSO IMPLEMENT
755 // MORE THAN ONE GENERATOR CONFIGURATION BY REPEATING THE matchArgs
756 // EXPRESSION MULTIPLE TIMES. IF THE FLAG staticInitOK IS TRUE, THEN IT IS
757 // SAFE TO PRECALCULATE INTERMEDIATE QUANTITIES IN initGenerator(), IF IT IS
758 // NOT SET THEN YOU SHOULD NOT ADVERTISE ANY GENERATOR METHOD THAT RELIES ON
759 // PRECALCULATIONS IN initGenerator().
760
761 // if (matchArgs(directVars,generateVars,x)) return 1;
762 return 0;
763}
764
765void CLASS_NAME::generateEvent(int code)
766{
767 // GENERATE SET OF OBSERVABLES DEFINED BY RETURN CODE ASSIGNED BY
768 // getGenerator(). RETURN THE GENERATED VALUES BY ASSIGNING THEM TO THE
769 // PROXY DATA MEMBERS THAT REPRESENT THE CHOSEN OBSERVABLES.
770
771 // assert(code==1);
772 // x = 0;
773 return;
774}
775)";
776
777 }
778 // clang-format on
779
780 std::ofstream ohf(className + ".h");
781 std::ofstream ocf(className + ".cxx");
782 std::string headerCode = hf.str();
783 std::string sourceCode = cf.str();
784 replaceAll(headerCode, "CLASS_NAME", className);
785 replaceAll(sourceCode, "CLASS_NAME", className);
786 replaceAll(headerCode, "BASE_NAME", baseName);
787 replaceAll(sourceCode, "BASE_NAME", baseName);
788 ohf << headerCode;
789 ocf << sourceCode;
790
791 return false;
792}
793
794namespace {
795
796////////////////////////////////////////////////////////////////////////////////
797
798std::string ClassFacIFace::create(RooFactoryWSTool &ft, const char *typeName, const char *instanceName,
799 std::vector<std::string> args)
800{
801 static int classCounter = 0;
802
803 string tn(typeName);
804
805 if (args.size() < 2) {
806 throw std::runtime_error(Form("RooClassFactory::ClassFacIFace::create() ERROR: CEXPR requires at least 2 "
807 "arguments (expr,var,...), but only %u args found",
808 (UInt_t)args.size()));
809 }
810
811 RooAbsArg *ret;
812 // Strip quotation marks from expression string
813 char expr[1024];
814 strncpy(expr, args[0].c_str() + 1, args[0].size() - 2);
815 expr[args[0].size() - 2] = 0;
816
817 RooArgList varList;
818
819 if (args.size() == 2) {
820 // Interpret 2nd arg as list
821 varList.add(ft.asLIST(args[1].c_str()));
822 } else {
823 for (unsigned int i = 1; i < args.size(); i++) {
824 varList.add(ft.asARG(args[i].c_str()));
825 }
826 }
827
828 string className;
829 while (true) {
830 className = Form("RooCFAuto%03d%s%s", classCounter, (tn == "CEXPR") ? "Pdf" : "Func", ft.autoClassNamePostFix());
831 TClass *tc = TClass::GetClass(className.c_str(), true, true);
832 classCounter++;
833 if (!tc) {
834 break;
835 }
836 }
837
838 if (tn == "CEXPR") {
839 ret = RooClassFactory::makePdfInstance(className, instanceName, expr, varList);
840 } else {
841 ret = RooClassFactory::makeFunctionInstance(className, instanceName, expr, varList);
842 }
843 if (!ret) {
844 throw std::runtime_error(
845 Form("RooClassFactory::ClassFacIFace::create() ERROR creating %s %s with RooClassFactory",
846 ((tn == "CEXPR") ? "pdf" : "function"), instanceName));
847 }
848
849 // Import object
850 ft.ws().import(*ret, RooFit::Silence());
851
852 // Import class code as well
853 ft.ws().importClassCode(ret->IsA());
854
855 return string(instanceName);
856}
857
858} // 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:2468
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:2968
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 init()
Inspect hardware capabilities, and load the optimal library for RooFit computations.
static const char * what
Definition stlLoader.cc:6