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);
}
Yes, I no longer get the warning! Thanks 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?
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
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
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…
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!
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
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
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.
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!