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());
87 for (RooAbsArg *arg : vars) {
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" << std::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" << std::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) {
509 hf <<
");" << std::endl ;
511 hf <<
"," << std::endl ;
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;
534 hf << "" << std::endl ;
537 for (std::size_t i=0 ; i<alist.size() ; i++) {
539 hf <<
" RooRealProxy " << alist[i] <<
" ;" << std::endl ;
541 hf <<
" RooCategoryProxy " << alist[i] <<
" ;" << std::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 <<
";" << std::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>
610CLASS_NAME::CLASS_NAME(const char *name, const char *title,
614 for (std::size_t i=0 ; i<alist.size() ; i++) {
616 cf <<
" RooAbsReal& _" << alist[i] ;
618 cf <<
" RooAbsCategory& _" << alist[i] ;
620 if (i<alist.size()-1) {
629 cf <<
" : BASE_NAME(name,title)," << std::endl ;
632 for (std::size_t i=0 ; i<alist.size() ; i++) {
633 cf <<
" " << alist[i] <<
"(\"" << alist[i] <<
"\",\"" << alist[i] <<
"\",this,_" << alist[i] <<
")" ;
634 if (i<alist.size()-1) {
640 cf <<
"{" << std::endl
644 <<
"CLASS_NAME::CLASS_NAME(CLASS_NAME const &other, const char *name)" << std::endl
645 <<
" : BASE_NAME(other,name)," << std::endl ;
647 for (std::size_t i=0 ; i<alist.size() ; i++) {
648 cf <<
" " << alist[i] <<
"(\"" << alist[i] <<
"\",this,other." << alist[i] <<
")" ;
649 if (i<alist.size()-1) {
659 <<
"double CLASS_NAME::evaluate() const " << std::endl
661 <<
" return CLASS_NAME_evaluate(" << listVars(alist) <<
");" << std::endl
664 <<
"void CLASS_NAME::doEval(RooFit::EvalContext &ctx) const" << std::endl
666 << declareVarSpans(alist)
668 <<
" std::size_t n = ctx.output().size();\n"
669 <<
" for (std::size_t i = 0; i < n; ++i) {\n"
670 <<
" ctx.output()[i] = CLASS_NAME_evaluate(" << getFromVarSpans(alist) <<
");\n"
675 std::stringstream varsGetters;
676 for (std::size_t i = 0; i < alist.size(); ++i) {
677 varsGetters <<
"arg." << alist[i];
678 if (i < alist.size() - 1) {
683 cf <<
"void RooFit::Experimental::codegenImpl(CLASS_NAME &arg, RooFit::Experimental::CodegenContext &ctx)\n"
685 <<
" ctx.addResult(&arg, ctx.buildCall(\"CLASS_NAME_evaluate\", " << varsGetters.str() <<
"));\n"
691 vector<string> intObs ;
692 vector<string> intExpr ;
695 if (!intExpression.empty()) {
696 const std::size_t bufSize = intExpression.size()+1;
697 std::vector<char> buf(bufSize);
698 strlcpy(buf.data(),intExpression.c_str(),bufSize) ;
699 char* ptr = strtok(buf.data(),
":") ;
701 intObs.push_back(ptr) ;
702 intExpr.push_back(strtok(
nullptr,
";")) ;
703 ptr = strtok(
nullptr,
":") ;
708int CLASS_NAME::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char */*rangeName*/) const
710 // Support also using the imaginary unit
711 using namespace std::complex_literals;
712 // To be able to also comile C code, we define a variable that behaves like the "I" macro from C.
713 constexpr auto I = 1i;
715 // LIST HERE OVER WHICH VARIABLES ANALYTICAL INTEGRATION IS SUPPORTED,
716 // ASSIGN A NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE
717 // BELOW ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X YOU CAN ALSO
718 // IMPLEMENT MORE THAN ONE ANALYTICAL INTEGRAL BY REPEATING THE matchArgs
719 // EXPRESSION MULTIPLE TIMES.
722 if (!intObs.empty()) {
723 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
724 cf <<
" if (matchArgs(allVars,analVars," << intObs[ii] <<
")) return " << ii+1 <<
" ; " << std::endl ;
727 cf <<
" // if (matchArgs(allVars,analVars,x)) return 1 ; " << std::endl ;
730 cf <<
" return 0 ; " << std::endl
735 << R
"(double CLASS_NAME::analyticalIntegral(int code, const char *rangeName) const
737 // RETURN ANALYTICAL INTEGRAL DEFINED BY RETURN CODE ASSIGNED BY
738 // getAnalyticalIntegral(). THE MEMBER FUNCTION x.min(rangeName) AND
739 // x.max(rangeName) WILL RETURN THE INTEGRATION BOUNDARIES FOR EACH
743 if (!intObs.empty()) {
744 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
745 cf <<
" if (code==" << ii+1 <<
") { return (" << intExpr[ii] <<
") ; } " << std::endl ;
748 cf <<
" // assert(code==1) ; " << std::endl
749 <<
" // return (x.max(rangeName)-x.min(rangeName)) ; " << std::endl ;
752 cf <<
" return 0 ; " << std::endl
753 <<
"} " << std::endl;
758int CLASS_NAME::getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool /*staticInitOK*/) const
760 // LIST HERE OVER WHICH VARIABLES INTERNAL GENERATION IS SUPPORTED, ASSIGN A
761 // NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE BELOW
762 // ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X. YOU CAN ALSO IMPLEMENT
763 // MORE THAN ONE GENERATOR CONFIGURATION BY REPEATING THE matchArgs
764 // EXPRESSION MULTIPLE TIMES. IF THE FLAG staticInitOK IS TRUE, THEN IT IS
765 // SAFE TO PRECALCULATE INTERMEDIATE QUANTITIES IN initGenerator(), IF IT IS
766 // NOT SET THEN YOU SHOULD NOT ADVERTISE ANY GENERATOR METHOD THAT RELIES ON
767 // PRECALCULATIONS IN initGenerator().
769 // if (matchArgs(directVars,generateVars,x)) return 1;
773void CLASS_NAME::generateEvent(int code)
775 // GENERATE SET OF OBSERVABLES DEFINED BY RETURN CODE ASSIGNED BY
776 // getGenerator(). RETURN THE GENERATED VALUES BY ASSIGNING THEM TO THE
777 // PROXY DATA MEMBERS THAT REPRESENT THE CHOSEN OBSERVABLES.
788 std::ofstream ohf(className +
".h");
789 std::ofstream ocf(className +
".cxx");
790 std::string headerCode = hf.str();
791 std::string sourceCode = cf.str();
806std::string ClassFacIFace::create(
RooFactoryWSTool &ft,
const char *typeName,
const char *instanceName,
807 std::vector<std::string> args)
809 static int classCounter = 0;
813 if (args.size() < 2) {
814 throw std::runtime_error(
Form(
"RooClassFactory::ClassFacIFace::create() ERROR: CEXPR requires at least 2 "
815 "arguments (expr,var,...), but only %u args found",
822 strncpy(expr, args[0].c_str() + 1, args[0].
size() - 2);
823 expr[args[0].size() - 2] = 0;
827 if (args.size() == 2) {
831 for (
unsigned int i = 1; i < args.size(); i++) {
832 varList.
add(ft.
asARG(args[i].c_str()));
852 throw std::runtime_error(
853 Form(
"RooClassFactory::ClassFacIFace::create() ERROR creating %s %s with RooClassFactory",
854 ((tn ==
"CEXPR") ?
"pdf" :
"function"), instanceName));
863 return string(instanceName);
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int).
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.
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.
RooCmdArg Silence(bool flag=true)
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)