50using std::endl, std::vector, std::string;
57 create(
RooFactoryWSTool &ft,
const char *typeName,
const char *instanceName, std::vector<std::string> args)
override;
73bool makeAndCompileClass(std::string
const &baseClassName, std::string
const &
name, std::string
const &expression,
74 const RooArgList &vars, std::string
const &intExpression)
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}
84 _argNames.reserve(vars.
size());
85 _argsAreCategories.reserve(vars.
size());
87 _argNames.emplace_back(arg->GetName());
88 _argsAreCategories.emplace_back(arg->isCategory());
93 return other._baseClassName == _baseClassName && other._name == _name && other._expression == _expression &&
94 other._argNames == _argNames && other._argsAreCategories == _argsAreCategories &&
95 other._intExpression == _intExpression;
98 std::string _baseClassName;
100 std::string _expression;
101 std::vector<std::string> _argNames;
102 std::vector<bool> _argsAreCategories;
103 std::string _intExpression;
106 static std::vector<ClassInfo> infosVec;
107 static std::mutex infosVecMutex;
109 ClassInfo info{baseClassName,
name, expression, vars, intExpression};
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) {
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());
125 const std::lock_guard<std::mutex> lock(infosVecMutex);
127 infosVec.emplace_back(info);
129 std::string realArgNames;
130 std::string catArgNames;
133 if (!realArgNames.empty())
135 realArgNames += arg->GetName();
136 }
else if (arg->isCategory()) {
137 if (!catArgNames.empty())
139 catArgNames += arg->GetName();
141 oocoutE(
nullptr, InputArguments) <<
"RooClassFactory ERROR input argument " << arg->GetName()
142 <<
" is neither RooAbsReal nor RooAbsCategory and is ignored" << endl;
147 !intExpression.empty(),
false, intExpression);
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)
161 bool error = makeAndCompileClass(baseClassName, className, expression, vars, intExpression);
169 std::string
line = std::string(
"new ") + className +
"(\"" +
name +
"\",\"" +
name +
"\"";
179 argList +=
Form(
",*reinterpret_cast<RooAbsReal*>(0x%zx)",
reinterpret_cast<std::size_t
>(var));
184 if (var->isCategory()) {
185 argList +=
Form(
",*reinterpret_cast<RooAbsCategory*>(0x%zx)",
reinterpret_cast<std::size_t
>(var));
189 line += argList +
") ;";
200 std::string
const &intExpression)
202 return makeAndCompileClass(
"RooAbsPdf",
name, expression, vars, intExpression);
219 const RooArgList &vars, std::string
const &intExpression)
221 return makeAndCompileClass(
"RooAbsReal",
name, expression, vars, intExpression);
245 const RooArgList &vars, std::string
const &intExpression)
248 std::string tmpName(
name);
249 tmpName[0] = toupper(tmpName[0]);
250 string className =
"Roo" + tmpName +
"Func";
276 std::string
const &expression,
const RooArgList &vars,
277 std::string
const &intExpression)
279 return static_cast<RooAbsReal *
>(makeClassInstance(
"RooAbsRal", className,
name, expression, vars, intExpression));
290 const RooArgList &vars, std::string
const &intExpression)
293 std::string tmpName(
name);
294 tmpName[0] = toupper(tmpName[0]);
295 string className =
"Roo" + tmpName +
"Pdf";
321 std::string
const &expression,
const RooArgList &vars,
322 std::string
const &intExpression)
324 return static_cast<RooAbsPdf *
>(makeClassInstance(
"RooAbsPdf", className,
name, expression, vars, intExpression));
336 std::string
const &expression,
bool hasAnaInt,
bool hasIntGen,
337 std::string
const &intExpression)
339 return makeClass(
"RooAbsPdf",
name, argNames, catArgNames, expression, hasAnaInt, hasIntGen, intExpression);
359 std::string
const &expression,
bool hasAnaInt, std::string
const &intExpression)
361 return makeClass(
"RooAbsReal",
name, argNames, catArgNames, expression, hasAnaInt,
false, intExpression);
366std::string listVars(std::vector<std::string>
const &alist, std::vector<bool>
const &isCat = {})
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") <<
" ";
374 if (i < alist.size() - 1) {
381std::string declareVarSpans(std::vector<std::string>
const &alist)
383 std::stringstream ss;
384 for (std::size_t i = 0; i < alist.size(); ++i) {
386 <<
"std::span<const double> " << alist[i] <<
"Span = ctx.at(" << alist[i] <<
");\n";
391std::string getFromVarSpans(std::vector<std::string>
const &alist)
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) {
405void replaceAll(std::string &inOut, std::string_view
what, std::string_view with)
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());
413inline bool isSpecial(
char c)
415 return c !=
'_' && !std::isalnum(
c);
418bool isComplex(std::string
const &expression)
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)
452 std::string
const &realArgNames, std::string
const &catArgNames,
453 std::string
const &expression,
bool hasAnaInt,
bool hasIntGen,
454 std::string
const &intExpression)
458 if (realArgNames.empty() && catArgNames.empty()) {
459 oocoutE(
nullptr, InputArguments)
460 <<
"RooClassFactory::makeClass: ERROR: A list of input argument names must be given" << endl;
464 if (!intExpression.empty() && !hasAnaInt) {
465 oocoutE(
nullptr, InputArguments) <<
"RooClassFactory::makeClass: ERROR no analytical integration code "
466 "requestion, but expression for analytical integral provided"
472 vector<string> alist;
475 for (
auto const &token :
ROOT::Split(realArgNames,
",",
true)) {
476 alist.push_back(token);
477 isCat.push_back(
false);
479 for (
auto const &token :
ROOT::Split(catArgNames,
",",
true)) {
480 alist.push_back(token);
481 isCat.push_back(
true);
485 std::stringstream hf;
486 hf << R
"(/*****************************************************************************
489 * This code was autogenerated by RooClassFactory *
490 *****************************************************************************/
495#include <BASE_NAME.h>
496#include <RooRealProxy.h>
497#include <RooCategoryProxy.h>
498#include <RooAbsReal.h>
499#include <RooAbsCategory.h>
503class CLASS_NAME : public BASE_NAME {
506 CLASS_NAME(const char *name, const char *title,)";
510 for (i=0 ; i<alist.size() ; i++) {
512 hf <<
" RooAbsReal& _" ;
514 hf <<
" RooAbsCategory& _" ;
517 if (i==alist.size()-1) {
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); }
530 int getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char *rangeName=nullptr) const override;
531 double analyticalIntegral(int code, const char *rangeName=nullptr) const override;
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;
543 hf << "protected:" << endl
547 for (i=0 ; i<alist.size() ; i++) {
549 hf <<
" RooRealProxy " << alist[i] <<
" ;" << endl ;
551 hf <<
" RooCategoryProxy " << alist[i] <<
" ;" << endl ;
556 double evaluate() const override;
557 void doEval(RooFit::EvalContext &) const override;
558 void translate(RooFit::Detail::CodeSquashContext &ctx) const override;
562 ClassDefOverride(CLASS_NAME, 1) // Your description goes here...
567 << "inline double CLASS_NAME_evaluate(" << listVars(alist, isCat) <<
") ";
572 if (isComplex(expression)) {
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;
582 // ENTER EXPRESSION IN TERMS OF VARIABLE ARGUMENTS HERE
585 << " return " << expression <<
"; " << endl
589 hf <<
"\n#endif // CLASS_NAME_h";
591 std::stringstream cf;
593 cf << R
"(/*****************************************************************************
596 * This code was autogenerated by RooClassFactory *
597 *****************************************************************************/
599// Your description goes here...
601#include "CLASS_NAME.h"
603#include <RooAbsReal.h>
604#include <RooAbsCategory.h>
606#include <Riostream.h>
613CLASS_NAME::CLASS_NAME(const char *name, const char *title,
617 for (i=0 ; i<alist.size() ; i++) {
619 cf <<
" RooAbsReal& _" << alist[i] ;
621 cf <<
" RooAbsCategory& _" << alist[i] ;
623 if (i<alist.size()-1) {
632 cf <<
" : BASE_NAME(name,title)," << endl ;
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) {
647 <<
"CLASS_NAME::CLASS_NAME(CLASS_NAME const &other, const char *name)" << endl
648 <<
" : BASE_NAME(other,name)," << endl ;
650 for (i=0 ; i<alist.size() ; i++) {
651 cf <<
" " << alist[i] <<
"(\"" << alist[i] <<
"\",this,other." << alist[i] <<
")" ;
652 if (i<alist.size()-1) {
662 <<
"double CLASS_NAME::evaluate() const " << endl
664 <<
" return CLASS_NAME_evaluate(" << listVars(alist) <<
"); " << endl
667 <<
"void CLASS_NAME::doEval(RooFit::EvalContext &ctx) const " << endl
669 << declareVarSpans(alist)
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"
677cf <<
"void CLASS_NAME::translate(RooFit::Detail::CodeSquashContext &ctx) const\n"
679<<
" ctx.addResult(this, ctx.buildCall(\"CLASS_NAME_evaluate\", " << listVars(alist) <<
"));\n"
684 vector<string> intObs ;
685 vector<string> intExpr ;
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(),
":") ;
694 intObs.push_back(ptr) ;
695 intExpr.push_back(strtok(
nullptr,
";")) ;
696 ptr = strtok(
nullptr,
":") ;
701int CLASS_NAME::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char */*rangeName*/) const
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;
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.
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 ;
720 cf <<
" // if (matchArgs(allVars,analVars,x)) return 1 ; " << endl ;
723 cf <<
" return 0 ; " << endl
728 << R
"(double CLASS_NAME::analyticalIntegral(int code, const char *rangeName) const
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
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 ;
741 cf <<
" // assert(code==1) ; " << endl
742 <<
" // return (x.max(rangeName)-x.min(rangeName)) ; " << endl ;
745 cf <<
" return 0 ; " << endl
751int CLASS_NAME::getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool /*staticInitOK*/) const
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().
762 // if (matchArgs(directVars,generateVars,x)) return 1;
766void CLASS_NAME::generateEvent(int code)
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.
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);
799std::string ClassFacIFace::create(
RooFactoryWSTool &ft,
const char *typeName,
const char *instanceName,
800 std::vector<std::string> args)
802 static int classCounter = 0;
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",
815 strncpy(expr, args[0].c_str() + 1, args[0].
size() - 2);
816 expr[args[0].size() - 2] = 0;
820 if (args.size() == 2) {
824 for (
unsigned int i = 1; i < args.size(); i++) {
825 varList.
add(ft.
asARG(args[i].c_str()));
831 className =
Form(
"RooCFAuto%03d%s%s", classCounter, (tn ==
"CEXPR") ?
"Pdf" :
"Func", ft.autoClassNamePostFix());
845 throw std::runtime_error(
846 Form(
"RooClassFactory::ClassFacIFace::create() ERROR creating %s %s with RooClassFactory",
847 ((tn ==
"CEXPR") ?
"pdf" :
"function"), instanceName));
856 return string(instanceName);
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Bool_t operator==(const TDatime &d1, const TDatime &d2)
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Common abstract base class for objects that represent a value and a "shape" in RooFit.
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.
Abstract base class for objects that represent a real value and implements functionality common to al...
RooArgList is a container object that can hold multiple RooAbsArg objects.
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.
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.
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.
TClass * IsA() const override
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.