Fit multiple histograms with the same function

Hello,

I am facing the following problem: I have multiple histograms which I would like to fit with the same function. Some of the parameters should be tied together, while some other should be fitted independently. I can’t find a way to do that. Can somebody help me?

Thank you in advance

Nobody knows how I could do?

Hi,

to fit multiple histograms you can create a combined data set (using the ROOT::Fit::BinData class )and then fit. If you have different parameters for the histograms you would need to create then separate chi2 (or likelihood) objects and then create a combined one which can be minimized.
If you are interested I can write you an example on how to do this. RooFit also provides some tools for doing simultaneous fits

Best Regards

Lorenzo

Thank you Lorenzo for the answer. If you could write me a little example, it would indeed be very useful for me. Thank you.

I will send you an example, but I can done it only after next week (I’ll be away)

Best Regards

Lorenzo

Thank you that would be great.

Dominique

Hi,

I have attached two examples. In the first one a fit is done using a common function on two histograms, in the second one different function are used and one parameter is shared between the two functions. In this case a combined chi2 is built and used for fitting the two data sets.
Best Regards

Lorenzo
combinedFit.C (2.13 KB)
fit2Histo.C (763 Bytes)

Thank you very much Lorenzo, this is exactly what I need.

Maybe it would be good to add such an example in the tutorials? I’m sure I’m not the only one who is facing such a problem.

Best regards
Dominique

I do have one more question though. When using the ROOT::Fit::Fitter class, how do I specify to fix some parameters, and how can I define the fit range?

Thanks in advance

Hi,
attached is an updated macro where a range in the observable is set and some parameters are limited and others fixed using the ROOT::Fit::Fitter class

Best Regards

Lorenzo
combinedFit.C (3.38 KB)

Once again, thank you very much Lorenzo.

Cheers
Dominique

Hmm, I think there is a small error in the combinedFit.C, or I’m doing something wrong:

/home/lewhoo/WAF/sample/./combinedFit.C: In function ‘void combinedFit()’:
/home/lewhoo/WAF/sample/./combinedFit.C:105: error: no match for call to ‘(ROOT::Fit::DataRange) ()’
/opt/pi/ext/dload/root/include/Fit/DataRange.h:97: note: candidates are: std::pair<double, double> ROOT::Fit::DataRange::operator()(unsigned int) const

it is simply fixed by chaning

fB->SetRange(rangeB().first, rangeB().second);

to

  fB->SetRange(rangeB(0).first, rangeB(0).second);   

Hi,

Thank you for spotting this. The macro worked with my development version which was not yet committed in ROOT. Now these changes are in the trunk and it should work. For older versions (revision < 36558) the changes suggested before should be applied.

Best Regards

Lorenzo

Hi,

thanks for providing these examples! I managed to get the combinedFit.C macro running with ACliC in ROOT 5.26. However, when adopting these lines of code for my analysis executable, which is build using g++ and a MakeFile pointing to the cflags and libs from root-config, I am getting the following compiler error:

‘FillData’ is not a member of ‘ROOT::Fit’

If understand the documentation (*) correctly, including “Fit/SparseData.h” should provide access to the FillData methods in the ROOT::Fit namespace. I have tried including this and several other related headers but I was not able to get rid of the compiler error.

Inside the example it says: “this macro must be compiled with ACliC”. Does this means it will work only with ACliC???

Cheers,
Sebastian

*:
root.cern.ch/root/html526/ROOT__Fit.html

Hi,

For the ROOT::Fit::FillData function you need to

#include "HFitInterface.h"

I have attached a revised macro, which include the correction mentioned before, which works also with 5.26

Lorenzo
combinedFit.C (3.5 KB)

Thanks a lot, Lorenzo, for the quick reply last week! Including the HFitInterface header indeed did the trick. I guess this is one example for those cases in which the auto-generated documentation is not able to tell users the necessary include(s) for all methods listed on a common documentation page (here corresponding to the ROOT::Fit namespace), right?

I have two further, slightly related questions…

1.) Is it possible to increase the verbosity of the ROOT::Fit::Fitter using some simple option parameter? I am currently getting a segmentation violation during the fit and thought that some additional printout before the crash would help me debugging.

2.) Is it true that there are no default constructors defined for ROOT::Fit::Chi2Function and
ROOT::Math::WrappedMultiTF1? If this is the case: What are the reasons for not providing them? I missed the default constructors when trying to build arrays of objects from these classes.

Best regards,
Sebastian

Hi,
Here are the answers to your questions:

  1. You can try to increase the print level by doing:
fitter.Config().MinimizizerOptions().SetPrintLevel(3)

The default print level is 0.

  1. The Chi2Function class is designed to work with a function and a data set pointer, which are stored internally as references. It is not possible to have a default constructor.
    I could add a default one for the ROOT::Math::WrappedMultiTF1 if you really need.
    Why you don’t create a vector of object pointers ? IN this case you solve the problem of the default constructor.

Best Regards

Lorenzo

Hi Lorenzo,

yes, that is fine.

Thanks! This is helpful. Now I see that my crash occurs directly after:

FIRST CALL TO USER FUNCTION AT NEW START POINT, WITH IFLAG=4.

From the stack trace (attached) I see that the seg fault happens within WrappedMultiTF1::DoEvalPar. Playing around with some cout statements, I saw that the crash happens when calling (*fChi2_1)(p1), i.e. when evaluating the first of those two functions inside my GlobalChi2 object, although there are no crashes when evaluating this WrappedMultiTF1 with the same parameter settings outside the GlobalChi2 object. And I saw that the crash happens before actually entering my user defined function that I put into the WrappedMultiTF1, i.e. before really starting to calculate a function value.

  • What does WrappedMultiTF1::DoEvalPar do before actually calculating the function value?
  • For which x value will the function value be calculated first? The lower bound of the range that was set using ROOT::Fit::DataRange?

Sorry for asking for support with such vague problem description but it would take me some time to create a minimal example from my analysis macro.

Best,
Sebastian
trace.txt (2.91 KB)

Hi,
your crash will most probably happen in TF1::EvalPar because the array of parameter you are passing is not of the right size. The size of the array p1 used in (*fChi2_1)(p1) must be equal to the number of parameter of the function (TF1::GetNpar()).
To help you more I would need then to see the code,

Lorenzo

Hi,

I have realized in the meantime that my seg fault was due to the fact that I was creating all my TF1 using the same name:

  TF1* f[5];
  for(unsigned i=0; i<5; i++) {
    f[i] = new TF1("myFunc", myFunc, 0., 125., 14);
  }

Everything seemed fine when creating the functions like this and I was able to set their parameters and to calculate function values. Just when including these functions in the combined fit, it crashed since all functions but the very last one in the array were invalid. I solved this by giving individual names to all functions when creating them:

  TF1* f[5];
  for(unsigned i=0; i<5; i++) {
    TString fName = "myFunc_"; fName += i;
    f[i] = new TF1(fName, myFunc, 0., 125., 14);
  }

Coming back to the combinedFit.C example, I have another question. How can I set the initial step size for parameters in the fit?

I tried:

  fitter.Config().ParSettings(3).SetLimits(0,10000);
  fitter.Config().ParSettings(3).SetStepSize(5); // this is new

This compiles and the fitter does not complain about the settings at runtime, but I am still getting:

PARAMETER DEFINITIONS:
NO. NAME VALUE STEP SIZE LIMITS
[…]
4 Par_3 1.00000e+02 3.00000e+01 0.00000e+00 1.00000e+04
[…]

So the step size was not changed from 30 to 5…

Best regards,
Sebastian