Skip to content

Commit

Permalink
[RF] Implement proper factory interface for RooLagrangianMorphFunc
Browse files Browse the repository at this point in the history
This is to avoid having to do hacks with the `RooStringVar`.

Closes root-project#9845.
  • Loading branch information
guitargeek committed Dec 15, 2022
1 parent 1cb1703 commit 54a8aeb
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 108 deletions.
5 changes: 0 additions & 5 deletions roofit/roofit/inc/RooLagrangianMorphFunc.h
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ class RooLagrangianMorphFunc : public RooAbsReal {
typedef std::map<const std::string, FlagSet> FlagMap;

struct Config {

std::string observableName;
RooRealVar *observable = nullptr;
std::string fileName;
Expand All @@ -101,8 +100,6 @@ class RooLagrangianMorphFunc : public RooAbsReal {
};

RooLagrangianMorphFunc();
RooLagrangianMorphFunc(const char *name, const char *title, const char *filename, const char *observableName,
const RooArgSet &couplings, const RooArgSet &inputs);
RooLagrangianMorphFunc(const char *name, const char *title, const Config &config);
RooLagrangianMorphFunc(const RooLagrangianMorphFunc &other, const char *newName);

Expand Down Expand Up @@ -181,8 +178,6 @@ class RooLagrangianMorphFunc : public RooAbsReal {
void disableInterference(const std::vector<const char *> &nonInterfering);
void disableInterferences(const std::vector<std::vector<const char *>> &nonInterfering);

void addFolders(const RooArgList &folders);

bool hasCache() const;
RooLagrangianMorphFunc::CacheElem *getCache() const;
void updateSampleWeights();
Expand Down
142 changes: 94 additions & 48 deletions roofit/roofit/src/RooLagrangianMorphFunc.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,16 @@ describe the same process or not.
#include "RooRealVar.h"
#include "RooStringVar.h"
#include "RooWorkspace.h"
#include "RooFactoryWSTool.h"

#include "ROOT/StringUtils.hxx"
#include "TFile.h"
#include "TFolder.h"
#include "TH1.h"
#include "TMap.h"
#include "TParameter.h"
#include "TRandom3.h"
// stl includes

#include <algorithm>
#include <cmath>
#include <cstddef>
Expand Down Expand Up @@ -1774,34 +1777,6 @@ void RooLagrangianMorphFunc::collectInputs(TDirectory *file)
}
}

////////////////////////////////////////////////////////////////////////////////
/// convert the RooArgList folders into a simple vector of std::string

void RooLagrangianMorphFunc::addFolders(const RooArgList &folders)
{
for (auto const &folder : folders) {
RooStringVar *var = dynamic_cast<RooStringVar *>(folder);
const std::string sample(var ? var->getVal() : folder->GetName());
if (sample.empty())
continue;
_config.folderNames.push_back(sample);
}

TDirectory *file = openFile(_config.fileName);
TIter next(file->GetList());
TObject *obj = nullptr;
while ((obj = (TObject *)next())) {
auto f = readOwningFolderFromFile(file, obj->GetName());
if (!f)
continue;
std::string name(f->GetName());
if (name.empty())
continue;
_config.folderNames.push_back(name);
}
closeFile(file);
}

////////////////////////////////////////////////////////////////////////////////
/// print all the parameters and their values in the given sample to the console

Expand Down Expand Up @@ -1856,25 +1831,6 @@ RooLagrangianMorphFunc::RooLagrangianMorphFunc(const char *name, const char *tit
TRACE_CREATE
}

////////////////////////////////////////////////////////////////////////////////
/// constructor with proper arguments
RooLagrangianMorphFunc::RooLagrangianMorphFunc(const char *name, const char *title, const char *filename,
const char *observableName, const RooArgSet &couplings,
const RooArgSet &folders)
: RooAbsReal(name, title), _cacheMgr(this, 10, true, true), _physics("physics", "physics", this),
_operators("operators", "set of operators", this), _observables("observables", "morphing observables", this),
_binWidths("binWidths", "set of binWidth objects", this), _flags("flags", "flags", this)
{
_config.fileName = filename;
_config.observableName = observableName;
_config.couplings.add(couplings);
this->addFolders(folders);
this->init();
this->setup(false);

TRACE_CREATE
}

////////////////////////////////////////////////////////////////////////////////
/// setup this instance with the given set of operators and vertices
/// if own=true, the class will own the operators template `<class Base>`
Expand Down Expand Up @@ -3078,3 +3034,93 @@ RooLagrangianMorphFunc::makeRatio(const char *name, const char *title, RooArgLis
// same for denom
return make_unique<RooRatio>(name, title, num, denom);
}

// Register the factory interface

namespace {

// Helper function for factory interface
std::vector<std::string> asStringV(std::string const &arg)
{
std::vector<std::string> out;

for (std::string &tok : ROOT::Split(arg, ",{}", true)) {
if (tok[0] == '\'') {
out.emplace_back(tok.substr(1, tok.size() - 2));
} else {
throw std::runtime_error("Strings in factory expressions need to be in single quotes!");
}
}

return out;
}

class LMIFace : public RooFactoryWSTool::IFace {
public:
std::string
create(RooFactoryWSTool &, const char *typeName, const char *instName, std::vector<std::string> args) override;
};

std::string LMIFace::create(RooFactoryWSTool &ft, const char * /*typeName*/, const char *instanceName,
std::vector<std::string> args)
{
// Perform syntax check. Warn about any meta parameters other than the ones needed
const std::array<std::string, 4> funcArgs{{"fileName", "observableName", "couplings", "folders"}};
std::map<string, string> mappedInputs;

for (unsigned int i = 1; i < args.size(); i++) {
if (args[i].find("$fileName(") != 0 && args[i].find("$observableName(") != 0 &&
args[i].find("$couplings(") != 0 && args[i].find("$folders(") != 0 && args[i].find("$NewPhysics(") != 0) {
throw std::string(Form("%s::create() ERROR: unknown token %s encountered", instanceName, args[i].c_str()));
}
}

for (unsigned int i = 0; i < args.size(); i++) {
if (args[i].find("$NewPhysics(") == 0) {
vector<string> subargs = ft.splitFunctionArgs(args[i].c_str());
for (const auto &subarg : subargs) {
std::vector<std::string> parts = ROOT::Split(subarg, "=");
if (parts.size() == 2) {
ft.ws().arg(parts[0].c_str())->setAttribute("NewPhysics", atoi(parts[1].c_str()));
} else
throw std::string(Form("%s::create() ERROR: unknown token %s encountered, check input provided for %s",
instanceName, subarg.c_str(), args[i].c_str()));
}
} else {
std::vector<string> subargs = ft.splitFunctionArgs(args[i].c_str());
if (subargs.size() == 1) {
string expr = ft.processExpression(subargs[0].c_str());
for (auto const &param : funcArgs) {
if (args[i].find(param) != string::npos)
mappedInputs[param] = subargs[0];
}
} else
throw std::string(
Form("Incorrect number of arguments in %s, have %d, expect 1", args[i].c_str(), (Int_t)subargs.size()));
}
}

RooLagrangianMorphFunc::Config config;
config.fileName = asStringV(mappedInputs["fileName"])[0];
config.observableName = asStringV(mappedInputs["observableName"])[0];
config.folderNames = asStringV(mappedInputs["folders"]);
config.couplings.add(ft.asLIST(mappedInputs["couplings"].c_str()));

ft.ws().import(RooLagrangianMorphFunc{instanceName, instanceName, config}, RooFit::Silence());

return instanceName;
}

static Int_t init();

int dummy = init();

static Int_t init()
{
RooFactoryWSTool::IFace *iface = new LMIFace;
RooFactoryWSTool::registerSpecial("lagrangianmorph", iface);
(void)dummy;
return 0;
}

} // namespace
55 changes: 0 additions & 55 deletions roofit/roofitcore/src/RooFactoryWSTool.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ static Int_t init()
// Miscellaneous
RooFactoryWSTool::registerSpecial("dataobs",iface) ;
RooFactoryWSTool::registerSpecial("set",iface) ;
RooFactoryWSTool::registerSpecial("lagrangianmorph",iface) ;

(void) dummy;
return 0 ;
Expand Down Expand Up @@ -2015,60 +2014,6 @@ std::string RooFactoryWSTool::SpecialsIFace::create(RooFactoryWSTool& ft, const
// prod::name[a,b,c]
ft.prodfunc(instName,pargs) ;

} else if (cl == "lagrangianmorph") {
// Perform syntax check. Warn about any meta parameters other than the ones needed
const std::array<std::string,4> funcArgs{{"fileName","observableName","couplings","folders"}};
map<string,string> mapped_inputs;

for (unsigned int i=1 ; i<pargv.size() ; i++) {
if (pargv[i].find("$fileName(")!=0 &&
pargv[i].find("$observableName(")!=0 &&
pargv[i].find("$couplings(")!=0 &&
pargv[i].find("$folders(")!=0 &&
pargv[i].find("$NewPhysics(")!=0) {
throw string(Form("%s::create() ERROR: unknown token %s encountered",instName, pargv[i].c_str())) ;
}
}

char pargsmorph[BUFFER_SIZE];
pargsmorph[0] = 0;

for (unsigned int i=0 ; i<pargv.size() ; i++) {
if (pargv[i].find("$NewPhysics(")==0) {
vector<string> subargs = ft.splitFunctionArgs(pargv[i].c_str()) ;
for(const auto& subarg: subargs) {
char buf[BUFFER_SIZE];
strlcpy(buf, subarg.c_str(), BUFFER_SIZE);
char *save;
char *tok = R__STRTOK_R(buf, "=", &save);
vector<string> parts;
while (tok) {
parts.push_back(string(tok));
tok = R__STRTOK_R(0, "=", &save);
}
if (parts.size() == 2){
ft.ws().arg(parts[0].c_str())->setAttribute("NewPhysics",atoi(parts[1].c_str()));
}
else throw string(Form("%s::create() ERROR: unknown token %s encountered, check input provided for %s",instName,subarg.c_str(), pargv[i].c_str()));
}
}
else {
vector<string> subargs = ft.splitFunctionArgs(pargv[i].c_str()) ;
if (subargs.size()==1){
string expr = ft.processExpression(subargs[0].c_str());
for(auto const& param : funcArgs){
if(pargv[i].find(param)!=string::npos) mapped_inputs[param]=subargs[0];
}
}
else throw string(Form("Incorrect number of arguments in %s, have %d, expect 1",pargv[i].c_str(),(Int_t)subargs.size())) ;
}
}
for(auto const& param : funcArgs){
if(strlen(pargsmorph) > 0) strlcat(pargsmorph, ",", BUFFER_SIZE);
strlcat(pargsmorph, mapped_inputs[param].c_str(),BUFFER_SIZE);
}
ft.createArg("RooLagrangianMorphFunc",instName, pargsmorph);

} else if (cl=="expr") {

// expr::name['expr',var,var,...]
Expand Down

0 comments on commit 54a8aeb

Please sign in to comment.