Home | News | Documentation | Download

GetX or GetFunction goes wrong

histossss.root (22.8 KB)
Hi all, I am trying to find an x-value given a y-value of a sigmoid function that I fitted to a an efficiency plot (divided 2 histograms) . So, I used GetFunction to get my fitted function, and then I tried to use GetX to find my x-value. However, I get the warning that “null passed to a callee that requires a non-null argument: double x_value = sigmoid->GetX(1., 65, 72);”, so I think something went wrong with the GetFunction part but I’m not sure what… Thanks!

void Efficiency(){
  auto f = new TFile ("histossss.root");

  TH1D *k1 = (TH1D*)f->Get("notrigger");
  
  std::vector<std::string> TriggerCut = {"J20", "J40", "J50", "J75", "J100"};

  int n = TriggerCut.size();
  
  TH1D *h[n];  
  TGraphAsymmErrors *eff[n];
  TF1 *fit[n];
  
  std::vector<int> offset = {50, 75, 90, 125, 160};
  
  for (unsigned i = 0; i < n; i++) {
    f->GetObject(TString::Format("%s", TriggerCut[i].c_str()) , h[i]);    
    
    eff[i] = new TGraphAsymmErrors();
    eff[i]->Divide(h[i], k1);
    eff[i]->SetNameTitle("eff", "Trigger Efficiency"); 
  
    if (i == 0) eff[i]->SetLineColor(kRed-7);
    else if (i == 1) eff[i]->SetLineColor(kBlue+3);
    else if (i == 2) eff[i]->SetLineColor(kViolet+7);
    else if (i == 3) eff[i]->SetLineColor(kAzure+7);
    else eff[i]->SetLineColor(kGreen+1);
    if (i==0) eff[i]->Draw("ap");
    else eff[i]->Draw("p same");
    
    fit[i] = new TF1("sigm_%d", "(1/(1+ TMath::Exp(-[0]*(x-[1]))))", 0, 230);
    fit[i]->SetParNames("stretching", "x-axis");
    fit[i]->SetParameters(0.2, offset[i]);
    eff[i]->Fit("sigm_%d");
  }

 sigmoid = eff[0]->GetFunction("fit[0]");
 double x_value = sigmoid->GetX(1., 65, 72);
}

Maybe I’m wrong (@couet can confirm) but shouldn’t it be:

 sigmoid = eff[0]->GetFunction(fit[0]->GetName());
1 Like

Yes, I no longer get the warning! Thanks :slight_smile: Now, it says that my interval isn’t valid, and that my interval doesn’t contain a root… I changed my interval a bit, but I keep getting the same problem, even though looking at my plots, there should be a root?

OK, so that’s another question… It depends on your data. Maybe @couet can give you some advice

I am looking at it. Note also that you need to declare sigmoid

 auto sigmoid = eff[0]->GetFunction(fit[0]->GetName());
 if (sigmoid) double x_value = sigmoid->GetX(1., 65, 72);
1 Like

Thanks! It works if I ask for it to find the corresponding x-value if y = 0.99, but still nothing for y = 1…

That might be some rounding effect. I see that the full error message we get is:

Info in <ROOT::Math::BrentMethods::MinimStep>: Grid search failed to find a root in the  interval 
Info in <ROOT::Math::BrentMethods::MinimStep>: xmin = 65 xmax = 72 npts = 100
Error in <ROOT::Math::BrentRootFinder>: Interval does not contain a root
Error in <TF1::GetX>: [65.000000,72.000000] is not a valid interval

May be @moneta can comment about it ?

1 Like

I think the message is quite clear. Do you expect to have an existing X value for f(X)=1 in the [65,72] interval or not ?
If not, then try to use a larger interval. If yes then there is a bug and we need to investigate further

Lorenzo

I have expanded my interval, and apparently 0.99 is reached when x = 63.8. So I would expect 1 to be reached within 63 and 70 by looking at the graph, however, when I write 1 instead of 0.99 it tells me that my interval isn’t valid…

Elena

I was also wondering if anyone knows how to include errors in that x value. Because I have errors associated with my fitted sigmoid function, so there should be an error in my x value, but I don’t know how to get that error… Thanks!

Hi Lorenzo,

The function has a “plateau” at 1 … can it be a problem for GetX ?

Yes, it looks like the function reaches 1 for x = +infinity. Maybe is more interesting to find the X for
f(X) = 1-epsilon, where epsilon is something like 0.01

Lorenzo

1 Like

Hi,
For computing the errors properly I would use a parametric boostrapping techinique. Generate many different data sets as the one you observed, fit each of them to a sigmoid and then look at the spread of the obtained X values

Lorenzo

Hi Lorenzo,
I am not using a randomly generated dataset, but rather actual data (simulated data to be exact), does that technique still work then? Is there no way to get an error with GetX based on the error of my fit? Or would that not be a good error?

Hi,
Given an observed histogram, you can still use the function TH1::GetRandom to generate random histograms.
The problem with another technique such as standard error propagation will be much less reliable. The function is highly non linear and the fit parameter errors probably very correlated.

Lorenzo

1 Like

Hi, I would now like to put this in my for loop, so that I get the x_value for my 5 plots. I tried:

void Efficiency(){
  auto f = new TFile ("histossss.root");

  TH1D *k1 = (TH1D*)f->Get("notrigger");
  
  std::vector<std::string> TriggerCut = {"J20", "J40", "J50", "J75", "J100"};
  std::vector<double> xmin = {60., 85., 100., 140., 190.};
  std::vector<double> xmax = {70., 100., 115., 155., 230.};

  int n = TriggerCut.size();
  
  TH1D *h[n];  
  TGraphAsymmErrors *eff[n];
  TF1 *fit[n];
  TF1 *sigmoid [n];
  
  std::vector<int> offset = {50, 75, 90, 125, 160};
  
  for (unsigned i = 0; i < n; i++) {
    f->GetObject(TString::Format("%s", TriggerCut[i].c_str()) , h[i]);    
    
    eff[i] = new TGraphAsymmErrors();
    eff[i]->Divide(h[i], k1);
    eff[i]->SetNameTitle("eff", "Trigger Efficiency"); 
  
    if (i == 0) eff[i]->SetLineColor(kRed-7);
    else if (i == 1) eff[i]->SetLineColor(kBlue+3);
    else if (i == 2) eff[i]->SetLineColor(kViolet+7);
    else if (i == 3) eff[i]->SetLineColor(kAzure+7);
    else eff[i]->SetLineColor(kGreen+1);
    if (i==0) eff[i]->Draw("ap");
    else eff[i]->Draw("p same");
    
    fit[i] = new TF1("sigm_%d", "(1/(1+ TMath::Exp(-[0]*(x-[1]))))", 0, 230);
    fit[i]->SetParNames("stretching", "x-axis");
    fit[i]->SetParameters(0.2, offset[i]);
    eff[i]->Fit("sigm_%d");

    sigmoid[i] = eff[i]->GetFunction(fit[i]->GetName()); 
    double x_value[i] = sigmoid[i]->GetX(0.99, xmin[i], xmax[i]);
  }

}

But I get the error: “Variable-sized object may not be initialised: double x_value[i] = sigmoid[i]->GetX(0.99, xmin[i], xmax[i])”. Do you know what is going wrong? Thanks!

You have to declare x_value as a vector.
Before the loop add the line

std::vector<double> x_value(n); 
1 Like