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