51using std::endl, std::vector, std::string;
58 create(
RooFactoryWSTool &ft,
const char *typeName,
const char *instanceName, std::vector<std::string> args)
override;
74bool makeAndCompileClass(std::string
const &baseClassName, std::string
const &
name, std::string
const &expression,
75 const RooArgList &vars, std::string
const &intExpression)
81 ClassInfo(std::string
const &baseClassName, std::string
const &
name, std::string
const &expression,
82 const RooArgList &vars, std::string
const &intExpression)
83 : _baseClassName{baseClassName}, _name{
name}, _expression{expression}, _intExpression{intExpression}
85 _argNames.reserve(vars.
size());
86 _argsAreCategories.reserve(vars.
size());
88 _argNames.emplace_back(arg->GetName());
89 _argsAreCategories.emplace_back(arg->isCategory());
94 return other._baseClassName == _baseClassName && other._name == _name && other._expression == _expression &&
95 other._argNames == _argNames && other._argsAreCategories == _argsAreCategories &&
96 other._intExpression == _intExpression;
99 std::string _baseClassName;
101 std::string _expression;
102 std::vector<std::string> _argNames;
103 std::vector<bool> _argsAreCategories;
104 std::string _intExpression;
107 static std::vector<ClassInfo> infosVec;
108 static std::mutex infosVecMutex;
110 ClassInfo info{baseClassName,
name, expression, vars, intExpression};
113 auto found = std::find_if(infosVec.begin(), infosVec.end(), [&](
auto const &elem) { return elem._name == name; });
114 if (found != infosVec.end()) {
115 if (*found == info) {
118 std::stringstream ss;
119 ss <<
"RooClassFactory ERROR The type, expressions, or variables for the class \"" <<
name
120 <<
"\" are not identical to what you passed last time this class was compiled! This is not allowed.";
121 oocoutE(
nullptr, InputArguments) << ss.str() << std::endl;
122 throw std::runtime_error(ss.str());
126 const std::lock_guard<std::mutex> lock(infosVecMutex);
128 infosVec.emplace_back(info);
130 std::string realArgNames;
131 std::string catArgNames;
134 if (!realArgNames.empty())
136 realArgNames += arg->GetName();
137 }
else if (arg->isCategory()) {
138 if (!catArgNames.empty())
140 catArgNames += arg->GetName();
142 oocoutE(
nullptr, InputArguments) <<
"RooClassFactory ERROR input argument " << arg->GetName()
143 <<
" is neither RooAbsReal nor RooAbsCategory and is ignored" << endl;
148 !intExpression.empty(),
false, intExpression);
158RooAbsReal *makeClassInstance(std::string
const &baseClassName, std::string
const &className, std::string
const &
name,
159 std::string
const &expression,
const RooArgList &vars, std::string
const &intExpression)
162 bool error = makeAndCompileClass(baseClassName, className, expression, vars, intExpression);
170 std::string
line = std::string(
"new ") + className +
"(\"" +
name +
"\",\"" +
name +
"\"";
180 argList +=
Form(
",*reinterpret_cast<RooAbsReal*>(0x%zx)",
reinterpret_cast<std::size_t
>(var));
185 if (var->isCategory()) {
186 argList +=
Form(
",*reinterpret_cast<RooAbsCategory*>(0x%zx)",
reinterpret_cast<std::size_t
>(var));
190 line += argList +
") ;";
201 std::string
const &intExpression)
203 return makeAndCompileClass(
"RooAbsPdf",
name, expression, vars, intExpression);
220 const RooArgList &vars, std::string
const &intExpression)
222 return makeAndCompileClass(
"RooAbsReal",
name, expression, vars, intExpression);
246 const RooArgList &vars, std::string
const &intExpression)
249 std::string tmpName(
name);
250 tmpName[0] = toupper(tmpName[0]);
251 string className =
"Roo" + tmpName +
"Func";
277 std::string
const &expression,
const RooArgList &vars,
278 std::string
const &intExpression)
280 return static_cast<RooAbsReal *
>(makeClassInstance(
"RooAbsRal", className,
name, expression, vars, intExpression));
291 const RooArgList &vars, std::string
const &intExpression)
294 std::string tmpName(
name);
295 tmpName[0] = toupper(tmpName[0]);
296 string className =
"Roo" + tmpName +
"Pdf";
322 std::string
const &expression,
const RooArgList &vars,
323 std::string
const &intExpression)
325 return static_cast<RooAbsPdf *
>(makeClassInstance(
"RooAbsPdf", className,
name, expression, vars, intExpression));
337 std::string
const &expression,
bool hasAnaInt,
bool hasIntGen,
338 std::string
const &intExpression)
340 return makeClass(
"RooAbsPdf",
name, argNames, catArgNames, expression, hasAnaInt, hasIntGen, intExpression);
360 std::string
const &expression,
bool hasAnaInt, std::string
const &intExpression)
362 return makeClass(
"RooAbsReal",
name, argNames, catArgNames, expression, hasAnaInt,
false, intExpression);
367std::string listVars(std::vector<std::string>
const &alist, std::vector<bool>
const &isCat = {})
369 std::stringstream ss;
370 for (std::size_t i = 0; i < alist.size(); ++i) {
371 if (!isCat.empty()) {
372 ss << (isCat[i] ?
"int" :
"double") <<
" ";
375 if (i < alist.size() - 1) {
382std::string declareVarSpans(std::vector<std::string>
const &alist)
384 std::stringstream ss;
385 for (std::size_t i = 0; i < alist.size(); ++i) {
387 <<
"std::span<const double> " << alist[i] <<
"Span = ctx.at(" << alist[i] <<
");\n";
392std::string getFromVarSpans(std::vector<std::string>
const &alist)
394 std::stringstream ss;
395 for (std::size_t i = 0; i < alist.size(); ++i) {
396 std::string
name = alist[i] +
"Span";
397 ss <<
name <<
".size() > 1 ? " <<
name <<
"[i] : " <<
name <<
"[0]";
398 if (i < alist.size() - 1) {
405inline bool isSpecial(
char c)
407 return c !=
'_' && !std::isalnum(
c);
410bool isComplex(std::string
const &expression)
414 for (std::size_t i = 0; i < expression.size(); ++i) {
415 bool leftOkay = (i == 0) || isSpecial(expression[i - 1]);
416 bool rightOkay = (i == expression.size() - 1) || isSpecial(expression[i + 1]);
417 if (expression[i] ==
'I' && leftOkay && rightOkay)
444 std::string
const &realArgNames, std::string
const &catArgNames,
445 std::string
const &expression,
bool hasAnaInt,
bool hasIntGen,
446 std::string
const &intExpression)
450 if (realArgNames.empty() && catArgNames.empty()) {
451 oocoutE(
nullptr, InputArguments)
452 <<
"RooClassFactory::makeClass: ERROR: A list of input argument names must be given" << endl;
456 if (!intExpression.empty() && !hasAnaInt) {
457 oocoutE(
nullptr, InputArguments) <<
"RooClassFactory::makeClass: ERROR no analytical integration code "
458 "requestion, but expression for analytical integral provided"
464 vector<string> alist;
467 for (
auto const &token :
ROOT::Split(realArgNames,
",",
true)) {
468 alist.push_back(token);
469 isCat.push_back(
false);
471 for (
auto const &token :
ROOT::Split(catArgNames,
",",
true)) {
472 alist.push_back(token);
473 isCat.push_back(
true);
477 std::stringstream hf;
478 hf << R
"(/*****************************************************************************
481 * This code was autogenerated by RooClassFactory *
482 *****************************************************************************/
487#include <BASE_NAME.h>
488#include <RooRealProxy.h>
489#include <RooCategoryProxy.h>
490#include <RooAbsReal.h>
491#include <RooAbsCategory.h>
495class CLASS_NAME : public BASE_NAME {
498 CLASS_NAME(const char *name, const char *title,)";
501 for (std::size_t i=0 ; i<alist.size() ; i++) {
503 hf <<
" RooAbsReal& _" ;
505 hf <<
" RooAbsCategory& _" ;
508 if (i==alist.size()-1) {
515 hf << R
"( CLASS_NAME(CLASS_NAME const &other, const char *name=nullptr);
516 TObject* clone(const char *newname) const override { return new CLASS_NAME(*this, newname); }
521 int getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char *rangeName=nullptr) const override;
522 double analyticalIntegral(int code, const char *rangeName=nullptr) const override;
528 int getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, bool staticInitOK=true) const override;
529 void initGenerator(int code) override {} // optional pre-generation initialization
530 void generateEvent(int code) override;
537 for (std::size_t i=0 ; i<alist.size() ; i++) {
539 hf <<
" RooRealProxy " << alist[i] <<
" ;" << endl ;
541 hf <<
" RooCategoryProxy " << alist[i] <<
" ;" << endl ;
546 double evaluate() const override;
547 void doEval(RooFit::EvalContext &) const override;
551 ClassDefOverride(CLASS_NAME, 1) // Your description goes here...
555namespace Experimental {
557void codegenImpl(CLASS_NAME &arg, CodegenContext &ctx);
559} // namespace Experimental
565 hf << "inline double CLASS_NAME_evaluate(" << listVars(alist, isCat) <<
")";
570 if (isComplex(expression)) {
572 // Support also using the imaginary unit
573 using namespace std::complex_literals;
574 // To be able to also comile C code, we define a variable that behaves like the "I" macro from C.
575 constexpr auto I = 1i;
580 // ENTER EXPRESSION IN TERMS OF VARIABLE ARGUMENTS HERE
583 << " return " << expression <<
";" << endl
587 hf <<
"\n#endif // CLASS_NAME_h";
589 std::stringstream cf;
591 cf << R
"(/*****************************************************************************
594 * This code was autogenerated by RooClassFactory *
595 *****************************************************************************/
597// Your description goes here...
599#include "CLASS_NAME.h"
601#include <RooAbsReal.h>
602#include <RooAbsCategory.h>
604#include <Riostream.h>
611CLASS_NAME::CLASS_NAME(const char *name, const char *title,
615 for (std::size_t i=0 ; i<alist.size() ; i++) {
617 cf <<
" RooAbsReal& _" << alist[i] ;
619 cf <<
" RooAbsCategory& _" << alist[i] ;
621 if (i<alist.size()-1) {
630 cf <<
" : BASE_NAME(name,title)," << endl ;
633 for (std::size_t i=0 ; i<alist.size() ; i++) {
634 cf <<
" " << alist[i] <<
"(\"" << alist[i] <<
"\",\"" << alist[i] <<
"\",this,_" << alist[i] <<
")" ;
635 if (i<alist.size()-1) {
645 <<
"CLASS_NAME::CLASS_NAME(CLASS_NAME const &other, const char *name)" << endl
646 <<
" : BASE_NAME(other,name)," << endl ;
648 for (std::size_t i=0 ; i<alist.size() ; i++) {
649 cf <<
" " << alist[i] <<
"(\"" << alist[i] <<
"\",this,other." << alist[i] <<
")" ;
650 if (i<alist.size()-1) {
660 <<
"double CLASS_NAME::evaluate() const " << endl
662 <<
" return CLASS_NAME_evaluate(" << listVars(alist) <<
");" << endl
665 <<
"void CLASS_NAME::doEval(RooFit::EvalContext &ctx) const" << endl
667 << declareVarSpans(alist)
669 <<
" std::size_t n = ctx.output().size();\n"
670 <<
" for (std::size_t i = 0; i < n; ++i) {\n"
671 <<
" ctx.output()[i] = CLASS_NAME_evaluate(" << getFromVarSpans(alist) <<
");\n"
676 std::stringstream varsGetters;
677 for (std::size_t i = 0; i < alist.size(); ++i) {
678 varsGetters <<
"arg." << alist[i];
679 if (i < alist.size() - 1) {
684 cf <<
"void RooFit::Experimental::codegenImpl(CLASS_NAME &arg, RooFit::Experimental::CodegenContext &ctx)\n"
686 <<
" ctx.addResult(&arg, ctx.buildCall(\"CLASS_NAME_evaluate\", " << varsGetters.str() <<
"));\n"
692 vector<string> intObs ;
693 vector<string> intExpr ;
696 if (!intExpression.empty()) {
697 const std::size_t bufSize = intExpression.size()+1;
698 std::vector<char> buf(bufSize);
699 strlcpy(buf.data(),intExpression.c_str(),bufSize) ;
700 char* ptr = strtok(buf.data(),
":") ;
702 intObs.push_back(ptr) ;
703 intExpr.push_back(strtok(
nullptr,
";")) ;
704 ptr = strtok(
nullptr,
":") ;
709int CLASS_NAME::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char */*rangeName*/) const
711 // Support also using the imaginary unit
712 using namespace std::complex_literals;
713 // To be able to also comile C code, we define a variable that behaves like the "I" macro from C.
714 constexpr auto I = 1i;
716 // LIST HERE OVER WHICH VARIABLES ANALYTICAL INTEGRATION IS SUPPORTED,
717 // ASSIGN A NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE
718 // BELOW ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X YOU CAN ALSO
719 // IMPLEMENT MORE THAN ONE ANALYTICAL INTEGRAL BY REPEATING THE matchArgs
720 // EXPRESSION MULTIPLE TIMES.
723 if (!intObs.empty()) {
724 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
725 cf <<
" if (matchArgs(allVars,analVars," << intObs[ii] <<
")) return " << ii+1 <<
" ; " << endl ;
728 cf <<
" // if (matchArgs(allVars,analVars,x)) return 1 ; " << endl ;
731 cf <<
" return 0 ; " << endl
736 << R
"(double CLASS_NAME::analyticalIntegral(int code, const char *rangeName) const
738 // RETURN ANALYTICAL INTEGRAL DEFINED BY RETURN CODE ASSIGNED BY
739 // getAnalyticalIntegral(). THE MEMBER FUNCTION x.min(rangeName) AND
740 // x.max(rangeName) WILL RETURN THE INTEGRATION BOUNDARIES FOR EACH
744 if (!intObs.empty()) {
745 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
746 cf <<
" if (code==" << ii+1 <<
") { return (" << intExpr[ii] <<
") ; } " << endl ;
749 cf <<
" // assert(code==1) ; " << endl
750 <<
" // return (x.max(rangeName)-x.min(rangeName)) ; " << endl ;
753 cf <<
" return 0 ; " << endl
759int CLASS_NAME::getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool /*staticInitOK*/) const
761 // LIST HERE OVER WHICH VARIABLES INTERNAL GENERATION IS SUPPORTED, ASSIGN A
762 // NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE BELOW
763 // ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X. YOU CAN ALSO IMPLEMENT
764 // MORE THAN ONE GENERATOR CONFIGURATION BY REPEATING THE matchArgs
765 // EXPRESSION MULTIPLE TIMES. IF THE FLAG staticInitOK IS TRUE, THEN IT IS
766 // SAFE TO PRECALCULATE INTERMEDIATE QUANTITIES IN initGenerator(), IF IT IS
767 // NOT SET THEN YOU SHOULD NOT ADVERTISE ANY GENERATOR METHOD THAT RELIES ON
768 // PRECALCULATIONS IN initGenerator().
770 // if (matchArgs(directVars,generateVars,x)) return 1;
774void CLASS_NAME::generateEvent(int code)
776 // GENERATE SET OF OBSERVABLES DEFINED BY RETURN CODE ASSIGNED BY
777 // getGenerator(). RETURN THE GENERATED VALUES BY ASSIGNING THEM TO THE
778 // PROXY DATA MEMBERS THAT REPRESENT THE CHOSEN OBSERVABLES.
789 std::ofstream ohf(className +
".h");
790 std::ofstream ocf(className +
".cxx");
791 std::string headerCode = hf.str();
792 std::string sourceCode = cf.str();
807std::string ClassFacIFace::create(
RooFactoryWSTool &ft,
const char *typeName,
const char *instanceName,
808 std::vector<std::string> args)
810 static int classCounter = 0;
814 if (args.size() < 2) {
815 throw std::runtime_error(
Form(
"RooClassFactory::ClassFacIFace::create() ERROR: CEXPR requires at least 2 "
816 "arguments (expr,var,...), but only %u args found",
823 strncpy(expr, args[0].c_str() + 1, args[0].
size() - 2);
824 expr[args[0].size() - 2] = 0;
828 if (args.size() == 2) {
832 for (
unsigned int i = 1; i < args.size(); i++) {
833 varList.
add(ft.
asARG(args[i].c_str()));
839 className =
Form(
"RooCFAuto%03d%s%s", classCounter, (tn ==
"CEXPR") ?
"Pdf" :
"Func", ft.autoClassNamePostFix());
853 throw std::runtime_error(
854 Form(
"RooClassFactory::ClassFacIFace::create() ERROR creating %s %s with RooClassFactory",
855 ((tn ==
"CEXPR") ?
"pdf" :
"function"), instanceName));
864 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.
void replaceAll(std::string &inOut, std::string_view what, std::string_view with)