1515#include < RooAbsCachedPdf.h>
1616#include < RooAddPdf.h>
1717#include < RooAddModel.h>
18+ #include < RooBinning.h>
1819#include < RooBinSamplingPdf.h>
1920#include < RooBinWidthFunction.h>
2021#include < RooCategory.h>
3334#include < RooLegacyExpPoly.h>
3435#include < RooLognormal.h>
3536#include < RooMultiVarGaussian.h>
37+ #include < RooStats/HistFactory/ParamHistFunc.h>
3638#include < RooPoisson.h>
3739#include < RooPolynomial.h>
3840#include < RooPolyVar.h>
@@ -532,6 +534,71 @@ class RooMultiVarGaussianFactory : public RooFit::JSONIO::Importer {
532534 }
533535};
534536
537+ class ParamHistFuncFactory : public RooFit ::JSONIO::Importer {
538+ public:
539+ bool importArg (RooJSONFactoryWSTool *tool, const JSONNode &p) const override
540+ {
541+ std::string name (RooJSONFactoryWSTool::name (p));
542+ RooArgList varList = tool->requestArgList <RooRealVar>(p, " variables" );
543+ if (!p.has_child (" axes" )) {
544+ std::stringstream ss;
545+ ss << " No axes given in '" << name << " '"
546+ << " . Using default binning (uniform; nbins=100). If needed, export the Workspace to JSON with a newer "
547+ << " Root version that supports custom ParamHistFunc binnings(>=6.38.00)." << std::endl;
548+ RooJSONFactoryWSTool::warning (ss.str ());
549+ tool->wsEmplace <ParamHistFunc>(name, varList, tool->requestArgList <RooAbsReal>(p, " parameters" ));
550+ return true ;
551+ }
552+ tool->wsEmplace <ParamHistFunc>(name, readBinning (p, varList), tool->requestArgList <RooAbsReal>(p, " parameters" ));
553+ return true ;
554+ }
555+
556+ private:
557+ RooArgList readBinning (const JSONNode &topNode, const RooArgList &varList) const
558+ {
559+ // Temporary map from variable name → RooRealVar
560+ std::map<std::string, std::unique_ptr<RooRealVar>> varMap;
561+
562+ // Build variables from JSON
563+ for (const JSONNode &node : topNode[" axes" ].children ()) {
564+ const std::string name = node[" name" ].val ();
565+ std::unique_ptr<RooRealVar> obs;
566+
567+ if (node.has_child (" edges" )) {
568+ std::vector<double > edges;
569+ for (const auto &bound : node[" edges" ].children ()) {
570+ edges.push_back (bound.val_double ());
571+ }
572+ obs = std::make_unique<RooRealVar>(name.c_str (), name.c_str (), edges.front (), edges.back ());
573+ RooBinning bins (obs->getMin (), obs->getMax ());
574+ for (auto b : edges)
575+ bins.addBoundary (b);
576+ obs->setBinning (bins);
577+ } else {
578+ obs = std::make_unique<RooRealVar>(name.c_str (), name.c_str (), node[" min" ].val_double (),
579+ node[" max" ].val_double ());
580+ obs->setBins (node[" nbins" ].val_int ());
581+ }
582+
583+ varMap[name] = std::move (obs);
584+ }
585+
586+ // Now build the final list following the order in varList
587+ RooArgList vars;
588+ for (int i = 0 ; i < varList.getSize (); ++i) {
589+ const auto *refVar = dynamic_cast <RooRealVar *>(varList.at (i));
590+ if (!refVar)
591+ continue ;
592+
593+ auto it = varMap.find (refVar->GetName ());
594+ if (it != varMap.end ()) {
595+ vars.addOwned (std::move (it->second )); // preserve ownership
596+ }
597+ }
598+ return vars;
599+ }
600+ };
601+
535602// /////////////////////////////////////////////////////////////////////////////////////////////////////
536603// specialized exporter implementations
537604// /////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -696,6 +763,7 @@ class RooFormulaArgStreamer : public RooFit::JSONIO::Exporter {
696763 expr.ReplaceAll (" TMath::Sin" , " sin" );
697764 expr.ReplaceAll (" TMath::Sqrt" , " sqrt" );
698765 expr.ReplaceAll (" TMath::Power" , " pow" );
766+ expr.ReplaceAll (" TMath::Erf" , " erf" );
699767 }
700768};
701769template <class RooArg_t >
@@ -952,6 +1020,47 @@ class RooExtendPdfStreamer : public RooFit::JSONIO::Exporter {
9521020 }
9531021};
9541022
1023+ class ParamHistFuncStreamer : public RooFit ::JSONIO::Exporter {
1024+ public:
1025+ std::string const &key () const override ;
1026+ bool exportObject (RooJSONFactoryWSTool *, const RooAbsArg *func, JSONNode &elem) const override
1027+ {
1028+ auto *pdf = static_cast <const ParamHistFunc *>(func);
1029+ elem[" type" ] << key ();
1030+ RooJSONFactoryWSTool::fillSeq (elem[" variables" ], pdf->dataVars ());
1031+ RooJSONFactoryWSTool::fillSeq (elem[" parameters" ], pdf->paramList ());
1032+ writeBinningInfo (pdf, elem);
1033+ return true ;
1034+ }
1035+
1036+ private:
1037+ void writeBinningInfo (const ParamHistFunc *pdf, JSONNode &elem) const
1038+ {
1039+ auto &observablesNode = elem[" axes" ].set_seq ();
1040+ // axes have to be ordered to get consistent bin indices
1041+ for (auto *var : static_range_cast<RooRealVar *>(pdf->dataVars ())) {
1042+ std::string name = var->GetName ();
1043+ RooJSONFactoryWSTool::testValidName (name, false );
1044+ JSONNode &obsNode = observablesNode.append_child ().set_map ();
1045+ obsNode[" name" ] << name;
1046+ if (var->getBinning ().isUniform ()) {
1047+ obsNode[" min" ] << var->getMin ();
1048+ obsNode[" max" ] << var->getMax ();
1049+ obsNode[" nbins" ] << var->getBins ();
1050+ } else {
1051+ auto &edges = obsNode[" edges" ];
1052+ edges.set_seq ();
1053+ double val = var->getBinning ().binLow (0 );
1054+ edges.append_child () << val;
1055+ for (int i = 0 ; i < var->getBinning ().numBins (); ++i) {
1056+ val = var->getBinning ().binHigh (i);
1057+ edges.append_child () << val;
1058+ }
1059+ }
1060+ }
1061+ }
1062+ };
1063+
9551064#define DEFINE_EXPORTER_KEY (class_name, name ) \
9561065 std::string const &class_name::key () const \
9571066 { \
@@ -989,6 +1098,7 @@ DEFINE_EXPORTER_KEY(RooRealIntegralStreamer, "integral");
9891098DEFINE_EXPORTER_KEY (RooDerivativeStreamer, " derivative" );
9901099DEFINE_EXPORTER_KEY (RooFFTConvPdfStreamer, " fft_conv_pdf" );
9911100DEFINE_EXPORTER_KEY (RooExtendPdfStreamer, " extend_pdf" );
1101+ DEFINE_EXPORTER_KEY (ParamHistFuncStreamer, " step" );
9921102
9931103// /////////////////////////////////////////////////////////////////////////////////////////////////////
9941104// instantiate all importers and exporters
@@ -1021,6 +1131,7 @@ STATIC_EXECUTE([]() {
10211131 registerImporter<RooDerivativeFactory>(" derivative" , false );
10221132 registerImporter<RooFFTConvPdfFactory>(" fft_conv_pdf" , false );
10231133 registerImporter<RooExtendPdfFactory>(" extend_pdf" , false );
1134+ registerImporter<ParamHistFuncFactory>(" step" , false );
10241135
10251136 registerExporter<RooAddPdfStreamer<RooAddPdf>>(RooAddPdf::Class (), false );
10261137 registerExporter<RooAddPdfStreamer<RooAddModel>>(RooAddModel::Class (), false );
@@ -1047,6 +1158,7 @@ STATIC_EXECUTE([]() {
10471158 registerExporter<RooDerivativeStreamer>(RooDerivative::Class (), false );
10481159 registerExporter<RooFFTConvPdfStreamer>(RooFFTConvPdf::Class (), false );
10491160 registerExporter<RooExtendPdfStreamer>(RooExtendPdf::Class (), false );
1161+ registerExporter<ParamHistFuncStreamer>(ParamHistFunc::Class (), false );
10501162});
10511163
10521164} // namespace
0 commit comments