[RF] Strange problems with RooRealVars with names containing slashes
Describe the bug
RooRealVars that have slashes ("/") in their name can cause a whole slew of issues. They should either be disallowed completely (replacing the slash in the name by something during construction) or the code needs to be adjusted to handle them correctly.
Expected behavior
RooRealVars should behave the same regardless of their name.
To Reproduce
Create RooDataHist with an observable that contains a slash in the name, build a RooHistFunc on top of it. Build some type of Pdf on top of this and fit it to the RooDataHist. The fit will treat the "slash" observable as a fit parameter rather than as an observable. Changing the name fixes that.
Additional context
This might seem like an arcane issue, but it can happen very easily because the new RooLagrangianMorphFunc uses the observable name to identify the locations of histograms in the source file, so any histogram that is a subfolder rather than at the toplevel will cause this issue to appear.
Hi @cburgard, thanks for reporting this! I struggle to reproduce this problem. I have implemented your instructions in the following code:
void repro() {
using namespace RooFit;
// Define the observable with slash in the name
RooRealVar x{"x/1", "x/1", 0.0, -10.0, 10.0};
// Build a RooDataHist, filled with uniform bin content
RooDataHist dh{"dh", "dh", x};
const std::size_t entriesPerBin = 100;
for(std::size_t i = 0; i < dh.numEntries(); ++i) {
for(std::size_t j = 0; j < entriesPerBin; ++j) {
dh.add(*dh.get(i), 1.0);
}
}
x.setVal(0.0);
// Create a RooHistFunc on top of it
RooHistFunc histFunc{"histFunc", "histFunc", x, dh};
// Define a model that uses the RooHistFunc.
RooRealVar frac{"frac", "frac", 0.5, 0.0, 1.0};
RooGaussian gaus{"gaus", "gaus", x, RooConst(2.0), RooConst(1.0)};
RooRealSumPdf model{"model", "model", {gaus, histFunc}, {frac}};
// Fit the model to the RooDataHist
std::unique_ptr<RooFitResult> result{model.fitTo(dh, PrintLevel(-1), Save(true))};
result->Print();
}
However, the fit result is just fine, listing only frac as a parameter as expected:
Floating Parameter FinalValue +/- Error
-------------------- --------------------------
frac 2.1309e-09 +/- 6.49e-0
How do I need to change this reproducer code to get the problem that you are reporting? And which ROOT version did you use?
Upon closer inspection, I am unable to reproduce this issue myself now. I will investigate further and close the issue if it magically disappeared.
For additional context, I will attach the script where the issue originally occurred, but seems to be gone now.
import ROOT
ROOT.gStyle.SetOptStat(0)
ROOT.PyConfig.IgnoreCommandLineOptions = True
ROOT.gROOT.SetBatch(True)
obsname = "CutGGF_TopoDPhill_truth/DPhill_V1_truth"
def makews():
# Create functions
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
# Setup observable that is to be morphed
obsvar = ROOT.RooRealVar("DPhill_V1_truth", "\#Delta \#phi_{truth}^{ll} [rad]", 0, 1.8)
cosa = ROOT.RooRealVar("cosa","cosa",-1.,1.)
kAww = ROOT.RooRealVar("kAww","kAww",1.)
kSM = ROOT.RooRealVar("kSM","kSM",1.)
Lambda = ROOT.RooRealVar("Lambda","Lambda",1000.)
kHww = ROOT.RooRealVar("kHww","kHww",0.)
gSM = ROOT.RooFormulaVar("_gSM" ,"cosa*kSM", ROOT.RooArgList(cosa,kSM))
gHww = ROOT.RooFormulaVar("_gHww" ,"cosa*kHww/Lambda", ROOT.RooArgList(cosa,kHww,Lambda))
gAww = ROOT.RooFormulaVar("_gAww" ,"sqrt(1-(cosa*cosa))*kAww/Lambda", ROOT.RooArgList(cosa,kAww,Lambda))
# Inputs to setup config
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
infilename = "samples-analyzed-NonSMggF-250722-o.root"
obsvar.setConstant(True)
par = "cosa"
samplelist = ["sig_X_ggf_BSM1", "sig_X_ggf_BSM2", "sig_X_ggf_SM"]
# Set Config
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
config = ROOT.RooLagrangianMorphFunc.Config()
config.fileName = infilename
config.observableName = obsname
config.folderNames = samplelist
config.couplings.add(gSM)
config.couplings.add(gHww)
config.couplings.add(gAww)
# Create morphing function
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
morphfunc = ROOT.RooLagrangianMorphFunc("morphfunc", "morphed dist. of DPhill", config)
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
# Extract input templates for plotting
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
morphfuncpdf = ROOT.RooWrapperPdf("morphpdf", "morphpdf",morphfunc)
ws = ROOT.RooWorkspace("workspace")
ws.Import(morphfuncpdf)
return ws
def plot(ws):
morphfunc = ws.function("morphfunc")
morphpdf = ws.pdf("morphpdf")
obsvar = ws.var(obsname)
UnfoldedFile = ROOT.TFile.Open("Unfolded.root","READ")
U1 = UnfoldedFile.Get("DPhill")
data_hist=ROOT.RooDataHist("dphill","dphill",[obsvar],U1)
morphpdf.fitTo(data_hist,ROOT.RooFit.SumW2Error(True))
morphfunc.printParameters();
ws = makews()
plot(ws)
I'll close this issue. Feel free to open a new one, should the problem pop up again in a reproducible form!