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" << 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 (
auto const &elem : alist) {
387 <<
"std::span<const double> " << elem <<
"Span = ctx.at(" << elem <<
");\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>
608// Workaround for https://github.com/llvm/llvm-project/issues/138683
609// Include <chrono> before <fstream> to ensure _FilesystemClock is defined
610// Can be removed once the upstream issue is fixed.
617CLASS_NAME::CLASS_NAME(const char *name, const char *title,
621 for (std::size_t i=0 ; i<alist.size() ; i++) {
623 cf <<
" RooAbsReal& _" << alist[i] ;
625 cf <<
" RooAbsCategory& _" << alist[i] ;
627 if (i<alist.size()-1) {
636 cf <<
" : BASE_NAME(name,title)," << std::endl ;
639 for (std::size_t i=0 ; i<alist.size() ; i++) {
640 cf <<
" " << alist[i] <<
"(\"" << alist[i] <<
"\",\"" << alist[i] <<
"\",this,_" << alist[i] <<
")" ;
641 if (i<alist.size()-1) {
647 cf <<
"{" << std::endl
651 <<
"CLASS_NAME::CLASS_NAME(CLASS_NAME const &other, const char *name)" << std::endl
652 <<
" : BASE_NAME(other,name)," << std::endl ;
654 for (std::size_t i=0 ; i<alist.size() ; i++) {
655 cf <<
" " << alist[i] <<
"(\"" << alist[i] <<
"\",this,other." << alist[i] <<
")" ;
656 if (i<alist.size()-1) {
666 <<
"double CLASS_NAME::evaluate() const " << std::endl
668 <<
" return CLASS_NAME_evaluate(" << listVars(alist) <<
");" << std::endl
671 <<
"void CLASS_NAME::doEval(RooFit::EvalContext &ctx) const" << std::endl
673 << declareVarSpans(alist)
675 <<
" std::size_t n = ctx.output().size();\n"
676 <<
" for (std::size_t i = 0; i < n; ++i) {\n"
677 <<
" ctx.output()[i] = CLASS_NAME_evaluate(" << getFromVarSpans(alist) <<
");\n"
682 std::stringstream varsGetters;
683 for (std::size_t i = 0; i < alist.size(); ++i) {
684 varsGetters <<
"arg." << alist[i];
685 if (i < alist.size() - 1) {
690 cf <<
"void RooFit::Experimental::codegenImpl(CLASS_NAME &arg, RooFit::Experimental::CodegenContext &ctx)\n"
692 <<
" ctx.addResult(&arg, ctx.buildCall(\"CLASS_NAME_evaluate\", " << varsGetters.str() <<
"));\n"
698 vector<string> intObs ;
699 vector<string> intExpr ;
702 if (!intExpression.empty()) {
703 const std::size_t bufSize = intExpression.size()+1;
704 std::vector<char> buf(bufSize);
705 strlcpy(buf.data(),intExpression.c_str(),bufSize) ;
706 char* ptr = strtok(buf.data(),
":") ;
708 intObs.push_back(ptr) ;
709 intExpr.push_back(strtok(
nullptr,
";")) ;
710 ptr = strtok(
nullptr,
":") ;
715int CLASS_NAME::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char */*rangeName*/) const
717 // Support also using the imaginary unit
718 using namespace std::complex_literals;
719 // To be able to also comile C code, we define a variable that behaves like the "I" macro from C.
720 constexpr auto I = 1i;
722 // LIST HERE OVER WHICH VARIABLES ANALYTICAL INTEGRATION IS SUPPORTED,
723 // ASSIGN A NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE
724 // BELOW ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X YOU CAN ALSO
725 // IMPLEMENT MORE THAN ONE ANALYTICAL INTEGRAL BY REPEATING THE matchArgs
726 // EXPRESSION MULTIPLE TIMES.
729 if (!intObs.empty()) {
730 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
731 cf <<
" if (matchArgs(allVars,analVars," << intObs[ii] <<
")) return " << ii+1 <<
" ; " << std::endl ;
734 cf <<
" // if (matchArgs(allVars,analVars,x)) return 1 ; " << std::endl ;
737 cf <<
" return 0 ; " << std::endl
742 << R
"(double CLASS_NAME::analyticalIntegral(int code, const char *rangeName) const
744 // RETURN ANALYTICAL INTEGRAL DEFINED BY RETURN CODE ASSIGNED BY
745 // getAnalyticalIntegral(). THE MEMBER FUNCTION x.min(rangeName) AND
746 // x.max(rangeName) WILL RETURN THE INTEGRATION BOUNDARIES FOR EACH
750 if (!intObs.empty()) {
751 for (std::size_t ii=0 ; ii<intObs.size() ; ii++) {
752 cf <<
" if (code==" << ii+1 <<
") { return (" << intExpr[ii] <<
") ; } " << std::endl ;
755 cf <<
" // assert(code==1) ; " << std::endl
756 <<
" // return (x.max(rangeName)-x.min(rangeName)) ; " << std::endl ;
759 cf <<
" return 0 ; " << std::endl
760 <<
"} " << std::endl;
765int CLASS_NAME::getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool /*staticInitOK*/) const
767 // LIST HERE OVER WHICH VARIABLES INTERNAL GENERATION IS SUPPORTED, ASSIGN A
768 // NUMERIC CODE FOR EACH SUPPORTED (SET OF) PARAMETERS. THE EXAMPLE BELOW
769 // ASSIGNS CODE 1 TO INTEGRATION OVER VARIABLE X. YOU CAN ALSO IMPLEMENT
770 // MORE THAN ONE GENERATOR CONFIGURATION BY REPEATING THE matchArgs
771 // EXPRESSION MULTIPLE TIMES. IF THE FLAG staticInitOK IS TRUE, THEN IT IS
772 // SAFE TO PRECALCULATE INTERMEDIATE QUANTITIES IN initGenerator(), IF IT IS
773 // NOT SET THEN YOU SHOULD NOT ADVERTISE ANY GENERATOR METHOD THAT RELIES ON
774 // PRECALCULATIONS IN initGenerator().
776 // if (matchArgs(directVars,generateVars,x)) return 1;
780void CLASS_NAME::generateEvent(int code)
782 // GENERATE SET OF OBSERVABLES DEFINED BY RETURN CODE ASSIGNED BY
783 // getGenerator(). RETURN THE GENERATED VALUES BY ASSIGNING THEM TO THE
784 // PROXY DATA MEMBERS THAT REPRESENT THE CHOSEN OBSERVABLES.
795 std::ofstream ohf(className +
".h");
796 std::ofstream ocf(className +
".cxx");
797 std::string headerCode = hf.str();
798 std::string sourceCode = cf.str();
813std::string ClassFacIFace::create(
RooFactoryWSTool &ft,
const char *typeName,
const char *instanceName,
814 std::vector<std::string> args)
816 static int classCounter = 0;
820 if (args.size() < 2) {
821 throw std::runtime_error(
Form(
"RooClassFactory::ClassFacIFace::create() ERROR: CEXPR requires at least 2 "
822 "arguments (expr,var,...), but only %u args found",
829 strncpy(expr, args[0].c_str() + 1, args[0].
size() - 2);
830 expr[args[0].size() - 2] = 0;
834 if (args.size() == 2) {
836 varList.
add(ft.asLIST(args[1].c_str()));
838 for (
unsigned int i = 1; i < args.size(); i++) {
839 varList.add(ft.asARG(args[i].c_str()));
845 className =
Form(
"RooCFAuto%03d%s%s", classCounter, (tn ==
"CEXPR") ?
"Pdf" :
"Func", ft.autoClassNamePostFix());
859 throw std::runtime_error(
860 Form(
"RooClassFactory::ClassFacIFace::create() ERROR creating %s %s with RooClassFactory",
861 ((tn ==
"CEXPR") ?
"pdf" :
"function"), instanceName));
868 ft.ws().importClassCode(ret->IsA());
870 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.
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.
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)