Simultaneous hist fit; ROOT::Math::IMultiGenFunction trouble

Hello ROOTers,

I am trying to fit several histograms simultaneously, and originally used code directly adapted from the example at http://root.cern.ch/root/html/tutorials/fit/combinedFit.C.html.

Now I need to use quite a few more histograms and functions, and I’d really like to avoid passing each function by hand. I’ve tried to adapt the code so that I pass the GlobalChi2 struct a container of pointers to ROOT::Math::IMultiGenFunction objects instead of passing each ROOT::Math::IMultiGenFunction explicitly, but I’m running into problems.

In the orignal code, objects of type ROOT::Fit::Chi2Function were created in the main body of the function and passed by reference to a struct calling for ROOT::Math::IMultiGenFunction objects. But when I pass by reference a container of ROOT::Fit::Chi2Function * to a struct expecting a container of ROOT::Math::IMultiGenFunction *, I get an error:

[quote]error: no matching function for call to ‘GlobalChi2::GlobalChi2(std::vector<ROOT::Fit::Chi2Function*, std::allocatorROOT::Fit::Chi2Function* >&)’
/afs/crc.nd.edu/user/a/arobert4/neutwall.git/3He26Mg_analysis/fit/combinedFit_vec.C:37: note: candidates are: GlobalChi2::GlobalChi2(std::vector<ROOT::Math::IMultiGenFunction*, std::allocatorROOT::Math::IMultiGenFunction* >&)[/quote]

I’m not sure how to fix this. Making containers of the objects themselves fails because ROOT::Fit::Chi2Function doesn’t have an assignment operator. As far as I can tell, I need to make a container of pointers.

My understanding is that these two different types are necessary - the ROOT::Fit::Chi2Function can accept data and a function, while the ROOT::Math::IMultiGenFunction allows me to define the () operator, necessary for the fitter.

I’ve also explored fixing this by passing the fitter a vector of structs, where each struct takes a function. But I’m really not sure how to make this work with the call to the ROOT::Fit::Fitter; I can’t seem to match the function call the original code is making with anything in the documentation.

The version of ROOT I’m using is 5.30, running on linux with x86_64 architecture.

Many thanks for your time!
combinedFit_vec_simple.C (2.76 KB)

Hello!

I’ve talked with our resident coding expert and done some poking, and I think I have the code working now.

The crucial change seemed to be in the constructor - in the original code, the constructor doesn’t do anything, and the fChi2_1 and fChi2_2 are given the addresses of the functions passed to GlobalChi2 in an initialization list.

GlobalChi2( ROOT::Math::IMultiGenFunction & f1, ROOT::Math::IMultiGenFunction & f2) : fChi2_1(&f1), fChi2_2(&f2) {}

Initially, I was trying to do the same thing, but with vector addresses. I couldn’t seem to get that to work (see above post). But if I use the constructor to work with elements of the vectors and don’t use an initialization list, the code compiles and runs!

GlobalChi2( vector< ROOT::Fit::Chi2Function * > & fVec) { for(unsigned int i = 0; i < fVec.size(); i++){ fChi2_Vec.push_back( fVec[i] ); } }

Where fChi2_Vec has type vector< const ROOT::Math::IMultiGenFunction * >.

Changing the constructor is not enough to get the code working, though. The type of vector that GlobalChi2 expects needed to be the same as the type of the vector passed to it when it’s initialized - hence the change in the type of argument to GlobalChi2. Perhaps that’s reasonable? But I don’t quite understand why the assignment of different types works fine when done on elements of the vector but not on the vectors themselves.

I’m also not sure what I’m giving up by using the constructor instead of the initialization list.

At any rate, the thing is working! If anyone has additional insights they’d like to share I’d be happy to hear them.
combinedFit_vec.C (4.22 KB)