TGraphErrors Multithread Fit with ROOT::Fit:Fitter

Hi,
Could someone help me to set up multi-threaded fitting with ROOT::Fit:Fitter for TGraphsErrors? I have seen examples with TH1::Fit and TGraph::Fit and also with the fitter but only using histograms and vectors. I need to perform a multi-threaded fitting with ROOT::Fit:Fitter of TGraphErrors with errors only on the y-axis. I believe I would need to use TThreadExecutor but I am not familiar with it or the multi-threading and I can not find any example on how to use it with TGraphErrors.
Many thanks for your help!

Many thanks for your reply and for pointing at this discussion. As I understand, they perform the TGraph::Fit with the MULTITHREAD option which is not available yet for TGraphErrors, and also I would need to use the ROOT::Fit:Fitter. I have used ROOT::EnableImplicitMT() but it does not make use of multithreading when fitting the TGraphErrors

Hi,
It is correct, multi-thread fittings not implement for TGraphErrors, when errors on the x coordinates are present.
One would need to add a new implementation of the function
FitUtil::EvaluateChi2Effective similar to FitUtil::EvaluateChi2.
If anybody wants to try implementing and provide a PR, it would be great, otherwise I can try implementing for next ROOT release if this is needed.

Cheers

Lorenzo

Dear Lorenzo,
Many thanks for your reply. The data I have to use only have errors on the y-axis but I need to use ROOT:Fit::Fitter. Following some examples I found with TThreadExecutor I tried to use it for TGraphErrors as follow:

auto fitResults = pool.Map([=](TGraphErrors* a) { return DoROOTFit(a, f1); }, m_TGraphErrors);

And I have the following problems:
test_FitParallel.C (2.8 KB)

  1. The fit gives an invalid result or just print results for one graph, and they differ from the fit results without the multi-thread. I have attached a simple working example reproducing this problem that prints the fit results for a TGraphErrors vector of size 2 with multithreading and without it. Here is the output I get:
root [0] 
Processing test_FitParallel.C...
--------------------> Fit with TThreadExecutor <--------------------------------
Minuit2Minimizer: Minimize with max-calls 1480 convergence for edm < 10 strategy 0
Minuit2Minimizer: Minimize with max-calls 1480 convergence for edm < 10 strategy 0
Warning in <Minuit2>: DavidonErrorUpdator delgam < 0 : first derivatives increasing along search line
Warning in <Minuit2>: VariableMetricBuilder Matrix not pos.def, gdel = 1.01454e+08 > 0
Warning in <Minuit2>: MnPosDef non-positive diagonal element in covariance matrix[ 3 ] = -1.46728e-06
Warning in <Minuit2>: MnPosDef Added to diagonal of Error matrix a value 0.500002
Warning in <Minuit2>: VariableMetricBuilder gdel = -3.45721e+13
Warning in <Minuit2>: VariableMetricBuilder No improvement in line search
Warning in <Minuit2>: VariableMetricBuilder No improvement in line search
Warning in <Minuit2>: VariableMetricBuilder Iterations finish without convergence; Edm 3.88947e+13 Requested 0.02
Warning in <Minuit2>: VariableMetricBuilder No convergence; Edm 7.32264e+12 is above tolerance 0.2
Warning in <Minuit2>: Minuit2Minimizer::Minimize Minimization did NOT converge, Edm is above max
Minuit2Minimizer : Invalid Minimum - status = 3
FVAL  = 20.2458
Edm   = 7.32264e+12
Nfcn  = 45
Minuit2Minimizer : Valid minimum - status = 0
FVAL  = 3384.47908572292499
Edm   = 8.39459238744864048e-05
Nfcn  = 28

****************************************
         Invalid FitResult  (status = 3 )
****************************************
Minimizer is Minuit2 / Migrad
p0Chi2	  =                       =            0	 +/-       20.2458
NDf                       =            6
Edm                       =  7.32264e+12
1.33638e-05
p1                       	  = 0	 +/-  1.33638e-05
p2	  = 0	 +/-  1.33638e-05
p3	  = 0	 +/-  1.33638e-05
NCalls                    =           45
p0                        =      2.73275   +/-   1.01628     
p1                        =       17.268   +/-   1.03283     

****************************************
Minimizer is Minuit2 / Migrad
Chi2                      =      3384.48
NDf                       =            6
p2Edm                       =  8.39459e-05
NCalls                                     =           28      
p0                        =            0   +/-   1.33638e-05 
p1                        =            0   +/-   1.33638e-05 
p2                        =            0   +/-   1.33638e-05 
 = 0.396728                 p3   +/-    =      1.07134
p3                        =     -19.5604   +/-   1           
0   +/-   1.33638e-05 
--------------------> Graph 1 Fit with ROOT::Fit <--------------------------------
Minuit2Minimizer: Minimize with max-calls 1480 convergence for edm < 10 strategy 0
Minuit2Minimizer : Valid minimum - status = 0
FVAL  = 2.5511665128769998
Edm   = 1.97303246105547783e-13
Nfcn  = 57
p0	  = 1.89396	 +/-  0.45889
p1	  = 11.2935	 +/-  1.84178
p2	  = 26.8916	 +/-  6.30252
p3	  = -41.0126	 +/-  5.26654

****************************************
Minimizer is Minuit2 / Migrad
Chi2                      =      2.55117
NDf                       =            6
Edm                       =  1.97303e-13
NCalls                    =           57
p0                        =      1.89396   +/-   0.45889     
p1                        =      11.2935   +/-   1.84178     
p2                        =      26.8916   +/-   6.30252     
p3                        =     -41.0126   +/-   5.26654     
--------------------> Graph 2 Fit with ROOT::Fit <--------------------------------
Minuit2Minimizer: Minimize with max-calls 1480 convergence for edm < 10 strategy 0
Minuit2Minimizer : Valid minimum - status = 0
FVAL  = 10.2046660515072034
Edm   = 3.09938819284710311e-19
Nfcn  = 78
p0	  = 2.07804	 +/-  0.710163
p1	  = -8.7692	 +/-  4.66136
p2	  = 102.998	 +/-  9.39174
p3	  = -82.0252	 +/-  5.26654

****************************************
Minimizer is Minuit2 / Migrad
Chi2                      =      10.2047
NDf                       =            6
Edm                       =  3.09939e-19
NCalls                    =           78
p0                        =      2.07804   +/-   0.710163    
p1                        =      -8.7692   +/-   4.66136     
p2                        =      102.998   +/-   9.39174     
p3                        =     -82.0252   +/-   5.26654     
root [1] 
[test_FitParallel.C|attachment](upload://oZRwqLOrpmDJ8HjLwgVeQb2B6WW.C) (2.8 KB)
[test_FitParallel.C|attachment](upload://oZRwqLOrpmDJ8HjLwgVeQb2B6WW.C) (2.8 KB)

  1. In this example, I use the same fit function for all the graphs but need to use a different fit function for each graph with different ranges and parameters set up. Is there any way to achieve that with the TThreadExecutor?

Thank you so much for any help!

Hi,
If you don’t have error on X you can run a single TGraph fit in multithread, by simply calling:

fitter.Fit(data, ROOT::EExecutionPolicy::kMultiThread ); 

However if you have only 10 points, it is not worth doing it.
If you have multiple TGraph’s you can do as in your example, but you have to create independent TF1 objects for each thread (i.e. each fit).
In your example above all the fits share the TF1 and its parameters and this will not work.

Lorenzo

Dear Lorenzo,
Thank you so much. I do have multiple graphs with more that 10 points.

I need to fit each graph many times changing the fit parameters each time. (I am changing the fit parameters randomly and keep only the fit results that meet certain chi2 condition.) In the example I made, I am not sure how create independent TF1 objects and use them as input in the TThreadExcecutor Map function along with the graphs vector. Could you help me to achieve this correctly?
Best regards and many thanks!

If implemented, this would be awesome. I’ve been waiting for some time now, but I still can’t find any good alternative.
Thank you very much,

Mattia