Saving multiple fit curves to ROOT file then summing

Dear Rooters,

I have several different individual fits to data in RooFit. I want to save each curve from fit, then sum them to get the sum of the fits.

There are some posts that sort of address this like

and

There is also ROOT: tutorials/roofit/rf607_fitresult.C Source File.

A snipped of what I tried is

r = model.fitTo(data, ROOT.RooFit.Extended(), ROOT.RooFit.Save(True))

model.plotOn(test_frame, ROOT.RooFit.Name("NAME"), ROOT.RooFit.Save(True))

f = ROOT.TFile("test.root","RECREATE")
r.Write("NAME")
f.Close()

I would assume this saves the fit result curve and saves it to the ROOT file. If I does, I’m not sure how to access it. After scanning through the ROOT file with TBrowser (and the one created in ROOT: tutorials/roofit/rf607_fitresult.C Source File), there doesn’t seem to be anything data. Maybe I’m just saving/reading incorrectly.

What would be the correct way to save the fit curves and access them, with the aim of summing the individual curves?

@StephanH Can you help?

Hi @Lepton86,

what do you want to do in the end? It sounds like you could use a fit model that is an addition of multiple PDFs. You would fit this to data once, and could create a histogram or a curve from the already summed results.

Some alternatives:
As you can see here:
https://root.cern.ch/doc/master/classRooAbsPdf.html#a8f802a3a93467d5b7b089e3ccaec0fa8
Save is only for saving fit results, that is, post fit parameters etc. It’s not saving curves.

If you really want curves in files, you should probably create histograms from the post-fit distributions.
That’s explained in the post you linked:

Here again the link to the relevant function for your convenience:
https://root.cern.ch/doc/master/classRooAbsReal.html#a6659d2c301e5cd65b83ee8c9422c2553

When you have the histogram, use something like

file.WriteObject(histogram, "name that it should have in the file");

Hi @StephanH,

In the end I actually do want to take the fits and sum them, not fit a sum of multiple PDFs.

For example, if I have a range of some mass M that is 1-10 GeV/c^{2}, I want to do fits in 10 individual 1 GeV/c^{2} bins. I want to save the fit curves and results from the 10 fits, then sum them and plot that sum against the full 1-10 GeV/c^{2} as to do some comparisons.

file.WriteObject(histogram, “name that it should have in the file”);

Yes, thank you but creating this histogram is what I need some clarification on. It would be helpful to see a simple example of its usage.

There is some example on page 57 here http://roofit.sourceforge.net/docs/tutorial/plot/roofit_tutorial_plot.pdf and page 102 here http://cicpi.ustc.edu.cn/indico/getFile.py/access?sessionId=2&resId=1&materialId=0&confId=678.

I try to reproduce them like this

model = ROOT.RooAddPdf("model", "total sig+bkg", ROOT.RooArgList(sig_pdf, bkg_pdf), ROOT.RooArgList(sig_yield, bkg_yield))

# data is an ntuple of M
r = model.fitTo(data, ROOT.RooFit.Extended(), ROOT.RooFit.Save(True))

model.plotOn(test_frame, ROOT.RooFit.Name("NAME"))

hist1 = model.createHistogram("fitCurve", M, ROOT.RooFit.IntrinsicBinning()))

f = ROOT.TFile("test.root","RECREATE")
f.WriteObject(hist1, "fitCurve")
f.Close()

Does this actually same the fit curve generated from fitting model to data, it doesn’t seem to? The normalization, given by the fitted values of sig_yield and bkg_yield, seems to not be correct. How is this done correctly with createHistogram?

UPDATE

@StephanH

After looking here How to save fit curve and erros in file (roofit)?.

This is kind of what I was looking to do

hist1 = test_frame.getCurve()
f = ROOT.TFile("test2.root","RECREATE")
f.WriteObject(hist1, "hName")
f.Close()

It seems to give the correct result, though without plotting it with the data the plot normalization looks distorted. Can you confirm this saves the fitted curve/model? I want to do this over multiple mass ranges and save each individual one as a histogram to a ROOT file, then same them. Is there am equivalent way to do this with createHistogram?

The tutorials have a few examples. (I find those by grep -R createHistogram $ROOTSYS/tutorials/):

No, it samples the PDF, and writes that into a histogram. The fit curves you see when plotting also sample the PDF, but they might sample it at different points. That depends on the binning you pass.

That’s because it’s creating a histogram of the PDF, that is, it’s normalised to unity. If you want it scaled to data, you need an extended fit model, and use RooFit::Extended(), as mentioned in the documentation of the function:
https://root.cern.ch/doc/master/classRooAbsReal.html#a6659d2c301e5cd65b83ee8c9422c2553

Alternatively, you just create the normalised histogram and use hist->Scale(nData) to scale it to the amount of data.

Yes, almost. It saves only the curve that was plotted. It doesn’t remember where it came from. That means that the resolution of the curve (the point spacing, the range) depend on how wide the plot range was and how many bins it had etc. If you now decide that you need more points or a different range, you cannot do it, because the PDF information is not saved. If you are happy with what you see, though, you can use that.

I don’t know what you mean. I guess you would have to attach a picture.

If you decide to save curves, note that RooCurve derives from TGraph, so you can use all the functions from TGraph to read out points etc.

The tutorials have a few examples. (I find those by grep -R createHistogram $ROOTSYS/tutorials/):

https://root.cern.ch/doc/master/rf301__composition_8C.html
https://root.cern.ch/doc/master/rf302__utilfuncs_8C.html

Thanks.

That’s because it’s creating a histogram of the PDF , that is, it’s normalised to unity. If you want it scaled to data, you need an extended fit model, and use RooFit::Extended() , as mentioned in the documentation of the function:
ROOT: RooAbsReal Class Reference

I overlooked that option. Thank you.

Yes, almost. It saves only the curve that was plotted. It doesn’t remember where it came from. That means that the resolution of the curve (the point spacing, the range) depend on how wide the plot range was and how many bins it had etc. If you now decide that you need more points or a different range, you cannot do it, because the PDF information is not saved. If you are happy with what you see, though, you can use that.

Yes, I think this is as close as I can get with this method.

I don’t know what you mean. I guess you would have to attach a picture.

Please disregard. It was a mistake.

If you decide to save curves, note that RooCurve derives from TGraph, so you can use all the functions from TGraph to read out points etc.

Yes. Then is there a way to create a TF1 from a RooCurve, something similar what’s shown here ROOT: TF1 Class Reference?

Using a lambda function as a general C++ functor object

TGraph * g = new TGraph(npointx, xvec, yvec); 
TF1 * f = new TF1("f",[&](double*x, double *p){ return p[0]*g->Eval(x[0]); }, xmin, xmax, 1);   
1 Like

Maybe, but way too complicated! This will be painful. Have you seen this?
https://root.cern.ch/doc/master/classTGraph.html#ab33753b0102ae87f91274cf277baa39b

Maybe, but way too complicated! This will be painful. Have you seen this?
ROOT: TGraph Class Reference

I have now. Thanks.

I will have to do some more reading to find an optimal solution. But for now I’ll mark this solved since I can capture the RooCurve. I’ll mark your response here Saving multiple fit curves to ROOT file then summing - #5 by StephanH as the solution with respect to that.

And thanks for your quick and helpful responses.

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