RooFit ignoring fit range when importing pdf from workspace

Dear RooFit experts,
when I try to fit a distribution with a pdf it looks like RooFit is ignoring the range if the pdf that I’m using to fit the data is being imported from a workspace. To reproduce this behaviour you can run

import ROOT

x = ROOT.RooRealVar("x","x",0.0,10.0)

# get the pdf from a workspace
in_file = ROOT.TFile.Open("myws.root")
ws = in_file.Get("w")
expo = ws.pdf("expo")

# generate data
c_expo_gen = ROOT.RooRealVar("c_expo_gen","c_expo_gen",-0.7)
expo_gen = ROOT.RooExponential("expo_gen","expo_gen",x,c_expo_gen)
data = expo_gen.generate(ROOT.RooArgSet(x),1000)

# set a fitting range
x.setRange("r",0.0,3.0)

# define the model
norm = ROOT.RooRealVar("norm","norm",0,1000)
model  = ROOT.RooAddPdf("model","model", ROOT.RooArgList(expo), ROOT.RooArgList(norm))

# fit to generated data
model.fitTo(data,ROOT.RooFit.Range("r"))
frame = x.frame()
data.plotOn(frame)
model.plotOn(frame)

# draw and save
c = ROOT.TCanvas("c","c",600,600)
frame.Draw()
c.SaveAs("fit_output.png")

where the input workspace (myws.root) can be created by running:

import ROOT
w = ROOT.RooWorkspace("w")
w.factory("Exponential::expo(x[0,10],c[-2.0,0.])")
of = ROOT.TFile("myws.root","recreate")
w.Write()
of.Close()

On the other hand, if the pdf is defined within the script the fit is performed within the range and the behaviour is as expected, i.e. if I subsitute the lines below the # get the pdf from a workspace comment with

# do not get the pdf from a workspace
c_expo = ROOT.RooRealVar("c_expo","c_expo",-2.,0.0)
expo = ROOT.RooExponential("expo","expo",x,c_expo)

I’ve tested it both in 6.12/07 and 6.26/04 root versions. While in the older version I don’t get any error message, in the second case i get the following warning message:

[#0] WARNING:Fitting -- None of the fit observables seem to know the range 'r'. This means that the full range will be used.

in both cases I didn’t manage to fit the data in the range, but I need to use the older root version.

Is there something that I’m missing?

Thanks a lot!
Leonardo

Hi,
Have you trued to set the range on the variable x that is stored in the workspace ? It seems when creating the workspace you are creating a new model, which is not aware of the range r. Try to do:

w.var("x").setRange("r",0.0,3.0)

Lorenzo

Dear Lorenzo,
thanks for the help! The warning disappears in 6.26/04 version but the problem is still there for both versions. I’ve also tried to do just model.fitTo(data,ROOT.RooFit.Range(0.0,3.0)) but it doesn’t work.
I don’t know if it’s worth mentioning that for the 6.26/04 version I also get the following error messages:

[#0] ERROR:Plotting -- Range 'fit_nll_model_expo_genData' not defined for variable 'x'. Ignoring ...
[#1] INFO:Plotting -- RooAbsPdf::plotOn(model) only plotting range 'fit_nll_model_expo_genData'
[#0] ERROR:Plotting -- Range 'fit_nll_model_expo_genData' not defined for variable 'x'. Ignoring ...
[#1] INFO:Plotting -- RooAbsPdf::plotOn(model) p.d.f. curve is normalized using explicit choice of ranges 'fit_nll_model_expo_genData'

while for the 6.12/07 version I don’t get any errors. Do you have any suggestion?

Leonardo

Hi @llunerti!

It’s no surprise that RooFit blows up in all kind of ways in your script.

RooFit assumes that all RooAbsArgs with the same name are the same object, or at least exact copies of each other. But you have now two RooRealVars called “x” that are in fact not exact copies: the one in the workspace has no range “r” defined, the one in your script does. You would get the same problem also if your would fail to sync up the default range by the way.

You need to avoid this situation by using the observable “x” from the workspace as well:

import ROOT

# get the observable and the pdf from a workspace
in_file = ROOT.TFile.Open("myws.root")
ws = in_file.Get("w")
x = ws["x"]
expo = ws["expo"]

# generate data
c_expo_gen = ROOT.RooRealVar("c_expo_gen", "c_expo_gen", -0.7)
expo_gen = ROOT.RooExponential("expo_gen", "expo_gen", x, c_expo_gen)
data = expo_gen.generate({x}, 1000)

# set a fitting range
x.setRange("r", 0.0, 3.0)

# define the model
norm = ROOT.RooRealVar("norm", "norm", 0, 1000)
model = ROOT.RooAddPdf("model", "model", [expo], [norm])

# fit to generated data
model.fitTo(data, Range="r", PrintLevel=-1)
frame = x.frame()
data.plotOn(frame)
model.plotOn(frame)

# draw and save
c = ROOT.TCanvas("c", "c", 600, 600)
frame.Draw()
c.SaveAs("fit_output.png")

The plotting errors in your second post will also go away like this.

Does that approach also work for your usecase?

Cheers,
Jonas

Dear @jonas,
your solution is solving my problem and I could apply it to my use case, thanks a lot! Thanks for the quick explanation as well :slight_smile:

Leonardo

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.