Std::bad_alloc in TF1 Fit

Hi All,

I’m trying to fit a TGraphAsymmErrors with the user coded function below. It is a sum of “top hats” (one step up and one step down) functions. The number of paramerters of the TF1 depends on the number of events in my dataset, for each event in my dataset there are three fixed parameters for this function. So the number of parameters of the TF1 is very large. The resulting TF1 has 1 free parameter and all the others are fixed. I then fit this TF1 to a TGraph.

[code]Double_t FitFn(Double_t *x, Double_t *par){

if (par[0] == 0 || par[1] == 0)
{
return 0;
}
double Q = ( -1 )/( par[0] );
double av_acc = 0.0;
double tophat = 0.0;
double denom = 0.0;
for ( int i=5; i < ( int(par[2])*2 )+5 ; i=i+2 )
{
tophat = 0.0;
if ( x[0] > par[i] && x[0] <= par[i+1] )
tophat = 1.0;
if ( par[i] == par[i+1] )
{
continue;
}
denom = 1 * ( TMath::Exp(par[i+1]*Q) - TMath::Exp(par[i]*Q) );
if ( denom == 0 )
{
return 0;
}
av_acc += tophat/denom;
}
double norm = -1 / ( par[0] * par[2]);
double blt = norm * TMath::Exp( - x[0]/par[0] ) * av_acc ;
double pdg = (1/par[1]) * TMath::Exp( -x[0]/par[1] ) * ( -1 /( TMath::Exp(-par[4]/par[1]) - TMath::Exp(-par[3]/par[1]) ) ) ;
return blt / pdg;
}[/code]

I have O(million) events, so I need the TF1 to have 0(3 Million) parameters. Currently there is a std::bad_alloc when running with only 50k events. It works with 10k events. I have traced this to a memory problem in TF1.Fit(). It isn’t a problem from somewhere else in my code.

Is it possible to fit a TF1 with so many parameters? Is there a better way to make such a function without using so many parameters in one TF1?

Thanks,
Kevin Maguire

Hi,

did you consider a linear or quadratic interpolation of your graph?

Cheers,
D

Hi D,

That is certainly an option. I could make a histogram of the “top hat” part and use a spline to make a smooth function using the bin values and the bin centers.

After some testing I see that it is possible to make the TF1 with 18 Million parameters. Then TF1::Eval() can be used to descretise the TF1 at a selection of points. From these discrete values I can interpolate a smooth function which can more easily be included in the fit.

Thanks,
Kevin Maguire

Hi All,

I can make a TSpline3 from my large TF1, call it A. I want to fit

What is the way to do this? I could make a user defined function of the form

Double_t FitFn(Double_t *x, Double_t *par)
{
  ... A->Eval() ...
  return val;
}

but how do I use A within this function? How do I make a product of a TF1 with a TSpline3 and then fit the product to some data? Is there a way to get the piecewise polynomials of the TSpline3 as TF1s? Note that A won’t change during the fit, it is completely fixed and has no parameters.

Thank,
Kevin

Hi,

In the end my solution was to take N sample points from my large TF1 (N=1000 say), which gives a list of x points X and a list of y points Y. Then pass these 2N values to a TF1 function as parameters and make the Spline within this function.

Double_t FitFn(Double_t *x, Double_t *par)
{
  double av_acc = 0.0;
  //make the array of X and Y values
  Double_t *xx = 0;
  Double_t *yy = 0;
  xx = new Double_t[ int(par[5]) ];
  yy = new Double_t[ int(par[5]) ];
  for (int i = 0; i < int(par[5]); i++)
    {
      xx[i] = par[8 + i];
      yy[i] = par[8 + int(par[5]) + i];
    }
  //make the spline interpolation of the acceptance function
  TSpline3 spline = TSpline3("av_acc", xx, yy, int(par[5]), "ble1", par[6], par[7]);
  av_acc = spline.Eval( x[0] );
  double blt = av_acc * (1/par[0]) * TMath::Exp( -x[0]/par[0] ) * ( -1 /( TMath::Exp(-par[4]/par[0]) - TMath::Exp(-par[3]/par[0]) )  ) ;
  double pdg = (1/par[1]) * TMath::Exp( -x[0]/par[1] ) * ( -1 /( TMath::Exp(-par[4]/par[1]) - TMath::Exp(-par[3]/par[1]) )  ) ;
  return blt / pdg;
}