1D fit using the sum of two user-defined functions

Hello eveybody,
I need to fit a TH1D using two different functions. Each one is defined on its own subrange. I found a similar topic, but I didn’t get help from that. Sorry if I am posting an already posted issue.

After the definition of the “total” function (parabola_1+parabola_2) the relative subranges are ignored in the “total” fit and I see only one parabola that spans over all the xaxis on my histo. The two separate fits on their subranges are working nicely. Here is the code of the fit. TH1D (named “sliceY0”) is defined between 0 and 20:


Double_t param[6];
TF1 f1 = new TF1(“f1”,"[0](x-[1])(x-[1]) + [2]",0,10);
TF1 f2 = new TF1(“f2”,"[0](x-[1])
(x-[1]) + [2]",10,20);

TF1 total = new TF1(“total”,"[0](x-[1])(x-[1]) + [2] + [3](x-[4])*(x-[4]) + [5]",0,20);

sliceY0->Fit(f1,“R”);
sliceY0->Fit(f2,“R+”);
f1->GetParameters(&param[0]);
f2->GetParameters(&param[3]);
total->SetParameters(param);
sliceY0->Fit(total,“R+”);

n.b. TF1 *total = new TF1(“total”,“f1(0) + f2(3)”,0,20); this is not working. Why not? it’s taken from the root “tutorials” directory.

Thanks a lot in advance.
Martino

Could you send a running script showing your problem? (and a data file if required)?

Rene

Hi Rene, thanks a lot for answering.
In attachment you can find a running macro with the .root file that is needed.

hope you can help me.
take care
Martino
rootForumMacro.cxx (1.74 KB)
inputTH3D.root (71.3 KB)

Hello,

I would like to refresh this topic, because I came to the same problem like Tino.

I define two fit functions: for signal and for background, then I create another function being a sum of two previous. And fit of this fails. But when I define one functions containing signal and background inside then fit works very good. Minimum working example attached.

Another issue I found. When I have this two separated functions for sig and bg, and I set parameters for them, then this parameters are also set for new function which contain this functions (parameters are copied, right?). But the same doesn’t work for parameter limits, I have to set them additionally to the new function. Why?

Greetings,
Rafał
c1.C (3.21 KB)

Your fit fails because you ave specified that your background pol1 first parameter has index 0 as does your signal fit’s first gaussian.
Simply change your bg tf1 to start with parameter index 6.

TF1 * fbg = new TF1("fbg", "pol1(6)", 1100, 1150);

After changing to pol1(6) it works, as you suggested, but then I am thinking whether we should consider this as a bug.

First of all, I would expect that after summing two or more functions the parameters are renumbered. This allows me to combine many functions despite fact how many parameters they have.

Secondly, if you look for the output of Print() function of both functions you will see

fit_sum : fsig+fbg Ndim= 1, Npar= 8, Noper= 5 fExpr[0] = gaus(0) action = 110 action param = 0 fExpr[1] = gaus(3) action = 110 action param = 3 fExpr[2] = + action = 1 action param = 0 fExpr[3] = pol1(0) action = 130 action param = 101 fExpr[4] = + action = 1 action param = 0 Optimized expression fExpr[0] = gaus(0) action = 110 action param = 0 fExpr[1] = gaus(3) action = 110 action param = 3 fExpr[2] = + action = 1 action param = 0 fExpr[3] = pol1(0) action = 130 action param = 101 fExpr[4] = + action = 1 action param = 0 Par 0 p0 = -511724 Par 1 p1 = 457.055 Par 2 p2 = -1.96031 Par 3 p3 = 37854.2 Par 4 p4 = 1112.65 Par 5 p5 = -8.50551 Par 6 p6 = 100 Par 7 p7 = -0.1 fit_full : gaus(0)+gaus(3)+pol1(6) Ndim= 1, Npar= 8, Noper= 5 fExpr[0] = gaus(0) action = 110 action param = 0 fExpr[1] = gaus(3) action = 110 action param = 3 fExpr[2] = + action = 1 action param = 0 fExpr[3] = pol1(6) action = 130 action param = 107 fExpr[4] = + action = 1 action param = 0 Optimized expression fExpr[0] = gaus(0) action = 110 action param = 0 fExpr[1] = gaus(3) action = 110 action param = 3 fExpr[2] = + action = 1 action param = 0 fExpr[3] = pol1(6) action = 130 action param = 107 fExpr[4] = + action = 1 action param = 0 Par 0 p0 = 39159.4 Par 1 p1 = 1115.23 Par 2 p2 = 1.70004 Par 3 p3 = 19312.2 Par 4 p4 = 1114.46 Par 5 p5 = 4.0956 Par 6 p6 = 128158 Par 7 p7 = -103.258
You can find that for fit_sum we have eight parameters, so parameter counting is proper but parameter numbering in raw or optimized expression is not. If you look then for the same output when background function is defined as pol1(6) we get

fit_sum : fsig+fbg Ndim= 1, Npar= 14, Noper= 5 fExpr[0] = gaus(0) action = 110 action param = 0 fExpr[1] = gaus(3) action = 110 action param = 3 fExpr[2] = + action = 1 action param = 0 fExpr[3] = pol1(6) action = 130 action param = 107 fExpr[4] = + action = 1 action param = 0 Optimized expression fExpr[0] = gaus(0) action = 110 action param = 0 fExpr[1] = gaus(3) action = 110 action param = 3 fExpr[2] = + action = 1 action param = 0 fExpr[3] = pol1(6) action = 130 action param = 107 fExpr[4] = + action = 1 action param = 0 Par 0 p0 = 39159.4 Par 1 p1 = 1115.23 Par 2 p2 = 1.70004 Par 3 p3 = 19312.2 Par 4 p4 = 1114.46 Par 5 p5 = 4.0956 Par 6 p6 = 128158 Par 7 p7 = -103.258 Par 8 p8 = 0 Par 9 p9 = 0 Par 10 p10 = 0 Par 11 p11 = 0 Par 12 p12 = 0 Par 13 p13 = 0
Here you have proper numerating of the parameters, but improper number of parameters: 14 instead of 8. And also Fit is manipulating parameters p6 and p7 which in respekt to bg functions should be parameters 0 and 1 of bg function, but pol1 starts from 6th, so p12 and p13 should be in fact adjusted.

TF1::Analyze uses the values within the parenthesis as the parameter start number for that predefined function, the parameters are not renumbered. The signal function, fsig, has fNpar = 6, since the background method starts on parameter 6 it’s fNpar = 8. The TF1::Analyse method then simply adds these fNpar values to get fit_sum.fNpar = 14.

Parameters 6 and 7 should be manipulated for the background function as that was indicated in the definition of fbg. Parameters 8-13 should not be in the parameter list as they do not impact the formula in anyway, but are there due to the summing of fNpar as described above.

This explains the resulting behavior, but I agree that one would expect the parameters to be renumbered when summing the values, this would need to have clear documentation. The downside to this renumbering would be that one can not simply take the fit_sum parameters and plug them into fbg to get only the background contribution, as in the following:

Instead, one would have to determine which parameters of fit_sum were background and map them onto the fbg parameters to get the proper values.

The fact that fbg.fNpar = 8 even though only two parameters have an impact is also misleading.

Thank you for this comprehensive explanation. I think that we both have feeling that something s there is not consistent. But now I know how to handle this.

[quote=“ksmith”]The downside to this renumbering would be that one can not simply take the fit_sum parameters and plug them into fbg to get only the background contribution, as in the following:

Instead, one would have to determine which parameters of fit_sum were background and map them onto the fbg parameters to get the proper values.[/quote]

Not big deal :slight_smile:

This will not work see the documentation for SetParameters(): [url]http://root.cern.ch/root/htmldoc/TFormula.html#TFormula:SetParameters[/url]

I was just stating that [b]if[/b] ROOT reindexed the parameters for fbg when summing them together to make fit_sum that the background parameters would be then p6 and p7 and if you used the the same array of parameters from fit_sum for fbg you would not get the background contribution since fbg uses parameters p0 and p1. This is [b]only[/b] a concern if TFormula is changed in ROOT, this is not the way it is now!

This will not work see the documentation for SetParameters(): http://root.cern.ch/root/htmldoc/TFormula.html#TFormula:SetParameters

I was just stating that if ROOT reindexed the parameters for fbg when summing them together to make fit_sum that the background parameters would be then p6 and p7 and if you used the the same array of parameters from fit_sum for fbg you would not get the background contribution since fbg uses parameters p0 and p1. This is only a concern if TFormula is changed in ROOT, this is not the way it is now!

[quote=“ksmith”]fbg->SetParameters(fit_sum->GetParameters() + fsig->GetNpar());
This will not work see the documentation for SetParameters(): http://root.cern.ch/root/htmldoc/TFormula.html#TFormula:SetParameters[/quote]
Why? “fit_sum->GetParameters()” returns “double *” which is a pointer and then " + fsig->GetNpar()" shifts the pointer value to address of par6 (of fit_sum) which is the first value of fbg parameters and will fit to pol1(0).

Sorry for the confusion. I meant that this will not work in your current application. If ROOT reindexed the parameters then your method of getting the parameters should be fine.

Any comment by the ROOT experts on whether this situation should be considered a bug?