Fit function uses initial parameter values

ROOT Version: 6.18/04
Platform: Linux

I defined a sigmoid function with 2 parameters (and set the initial parameter values). I am now trying to fit this function to a plot (called fun[1]), however my ‘fit’ always just takes my initial parameter values, even though that is definitely not the best fit. Most of the time I also get the message saying that STATUS = FAILED, a few times, however, I got STATUS = CONVERGED, but that result clearly wasn’t the best fit.

I tried:

TF1 *sigm = new TF1("sigm", "(1/(1+ TMath::Exp(-[0]*(x-[1]))))", 0, 230);
sigm->SetParameters(.2, 75.);
sigm->SetParLimits(0, .1, .4);
sigm->SetParLimits(1, 50, 90);
fun[1]->Fit(sigm);

Anyone knows what’s going wrong?

Hi,
hard to help without knowledge of fun[1] (a TH1? a TGraph?),
its values and errors.
Can you provide this information.

Cheers
Otto

Ah yes of course! fun[1] is the first curve (the red one, I called it eff[0] in my code). It’s the trigger efficiency (found by dividing 2 histograms). I have included my full code below. I hope this helps!

void Efficiency(){
  auto f = new TFile ("output.root");
  TH1D *k1 = (TH1D*)f->Get("Aftercut");
  
  std::vector<std::string> Cut = {"J30", "J40", "J50", "J75", "J100"};
  int n = Cut.size();
  TH1D *h[n];  
  TGraphAsymmErrors *eff[n];
  
  for (unsigned i = 0; i < n; i++) {
    f->GetObject(TString::Format("Beforecut", Cut[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]->Draw("ap");
    else eff[i]->Draw("p same");
  }
  
  TF1 *sigm = new TF1("sigm", "(1/(1+ TMath::Exp(-[0]*(x-[1]))))", 0, 230);
  sigm->SetParameters(.3, 50.);
  sigm->SetParLimits(0, .2, .8);
  sigm->SetParLimits(1, 35, 70);
  eff[0]->Fit(sigm);
}   
 
    
    

Hi,
sorry still no data, we need the root file with the histos
Otto

histos.root (23.5 KB)

Ah, I’m sorry :frowning:. I have no access to the data at the moment, but I have attached a root file which (hopefully) contains the histograms. They have different names in the file. Basically, in my code:

k1 is the one that starts with yCut_0.6/pT1_0/pT2_0/…
h[0] starts with L1_J20/…
h[1] starts with L1_J40/…
and so on for h[2], h[3] and h[4], with J50, J75, J100 respectively.

I hope this works…

Please provide a macro and a corresponding root file so that one can “reproduce” your problem.

histos.root (23.5 KB)

I attached a root file with the relevant histograms (please let me know if this somehow doesn’t work), and here is my macro:

void Efficiency(){
  auto f = new TFile ("histos.root");
  TH1D *k1 = (TH1D*)f->Get("yCut_0.6/pT1Cut_0/pT2Cut_0/LeadingJetPt");
  std::vector<std::string> TriggerCut = {"L1_J20", "L1_J40", "L1_J50", "L1_J75", "L1_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/yCut_0.6/pT1Cut_0/pT2Cut_0/LeadingJetPt", 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]->Draw("ap");
    else eff[i]->Draw("p same");
    
    fit[i] = new TF1("sigm_%d", "(1/(1+ TMath::Exp(-[0]*(x-[1]))))", 0, 230); // Sigmoid fit to turn-on curves
    fit[i]->SetParNames("stretching", "offset");
    fit[i]->SetParameters(0.2, offset[i]);
    eff[i]->Fit("sigm_%d");
  }
  

I don’t really believe you’ve actually tried to run this macro with this root file.

Yes, you’re right. My original root file contained many more irrelevant histograms, so I created a new one with only the relevant ones. I edited my macro in my previous post. It should work now I think.

Please DO try to run your macros before posting them here.

histossss.root (22.8 KB)

I am new to root, c++ and this forum, so I apologise. Here is the correct macro for the attached root file (I checked it this time).

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");
  }
}

Try: eff[i]->Fit(fit[i], "W"); // "W" or "EX0"

BTW: You probably meant: fit[i] = new TF1(TString::Format("sigm_%d", i), ...);, but note also that you do not need “separate” functions for each of your graphs.

Thanks a lot! That works! When running my macro, I get a warning saying: “Warning in TGraphAsymErrors::Divide: Number of graph points is different than histogram bins - 9824 points have been skipped skipped”. Do you perhaps know why I get this error and how to fix this? Thanks!

I guess it’s because your histograms have bins with zero contents.

@moneta do you think I should use the TEfficiency::Fit in this case? (my macro and root file are in a previous post). Because I’m not sure how to create a TEfficiency class (I read the documentation on it, but still not sure how to do this in my case)…
Thanks!

Yes you should use TEfficiency::Fit.
To create you need the original histograms, the numerator and the denominator that you used to compute the ratio. If you don’t have it can be problematic

Lorenzo

I read the documentation about the TEfficiency class, but I am not sure how to use it. I tried to create my efficiency using the TEfficiency class like this:

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];
  TEfficiency *eff[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]);    
    if (TEfficiency::CheckConsistency(h[i], k1)) {
       eff[i] = new TEfficiency(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");
  }
}

However, I get a lot of errors: including “error: reference to type ‘cons TH1’ could not bind to an lvalue of type ‘TH1D *’ : if (TEfficiency::CheckConsistency(h[i], k1))” and “error: no matching constructor for initialisation of ‘TEfficiency’: eff[i] = new TEfficiency(h[i], k1)”. Do you know what I am doing wrong? Thanks!

Hi,

As shown in the constructor documentation, see
https://root.cern.ch/doc/master/classTEfficiency.html#aa0e99b4161745fd3bee0ae5c0f58880e
you need to pass a reference to the histogram and not the pointer. In your case:

if (TEfficiency::CheckConsistency(*h[i], *k1)) {
       eff[i] = new TEfficiency(*h[i], *k1)
     }

However, I don’t see in your code where you create or get the histogram containing the events that pass the trigger section, the passed histogram, h[i]

Lorenzo

1 Like

Using the fit function I used in my macro, is there any way to only fit my plots for efficiencies that are higher than or equal to 80%? i.e. I’d like to set a range to my fit from 0.8 until 1, is this possible? Thanks!

Hi,
you should be able to set the desired range in the fitted function and then use option “R” in the TEfficiency::Fit method