Save TF1 in RDataFrame column

Hi,

Is it possible to store TF1 from a fit into RDataFrame column?

I am getting some seg faults. So I assume its not, but I am curious why as it would be very nice feature.

Saving one TF1 object with TF1 getFunc() is much more neat rather than writing something like:

double getPar1()
double getPar2()
double getPar3()
double getParChi2()
double getParNDF()

or

double getValue(par){
    if(par == "par1") return par1;
    if(par == "par2") return par2;
    if(par == "par3") return par3;
    if(par == "chi2") return chi2;
    if(par == "ndf") return ndf;
}

cheers,
Bohdan

Hi,
not sure what you mean with “saving”/“storing” a TF1 in a RDF column. You can definitely call a TF1 from a Define:

root [0] TF1 f("f", "sin(x)", 0, 6);
root [2] ROOT::RDataFrame(1).Define("x", [&]() { return f(3); }).Histo1D("x")->GetMean()
(double) 0.14112001

but I guess that’s not it.

Hi, @eguiraud

I meant something like this:

import ROOT

header = '''

TF1 getFitFunc(){
    TGraph gr;
    for(int i=0; i< 10; ++i) gr.SetPoint(i+1, i, i*i);
    gr.Fit("pol2");
    TF1 fit = *gr.GetFunction("pol2");
    return fit;
}

'''

ROOT.gInterpreter.Declare(header)
print(ROOT.RDataFrame(1).Define("func", "getFitFunc()").Define("par0", "func.GetParameter(0)").Histo1D("par0").GetMean())

Output:

...
*** Break *** segmentation violation
...

Hi,
it’s a lifetime issue, see the self-contained C++ reproducer below, with no RDF involved – the segfault goes away if you change TGraph gr to auto *gr = new TGraph() and then leak the TGraph:

#include <TF1.h>
#include <TGraph.h>

TF1 getFitFunc() {
  TGraph *gr = new TGraph();
  for (int i = 0; i < 10; ++i)
    gr->SetPoint(i + 1, i, i * i);
  gr->Fit("pol2");
  TF1 fit = *gr->GetFunction("pol2");
  delete gr; // comment to make the crash disappear
  return fit;
}

int main() {
  TF1 f = getFitFunc();
  f.GetParameter(0);
  return 0;
}

Inspecting the crash with gdb reveals the problem is in TF1’s destructor, where the TF1 object tries to deregister itself from its fParent object (the TGraph in this case, which is already out of scope in your implementation of getFitFunc).

I assume that your real use-case is more complicated so I won’t try to come up with a solution that might not apply to your case :slight_smile:

Cheers,
Enrico

As a suggestion, however: if you don’t need to re-evaluate the fit at every event, just use variables external to the event loop. If you need to evaluate the Fit at every event, maybe rather than returning the TF1 from getFitFunc you can return a struct or a vector with the fit parameters you need in further computations, so the only thing passed around is numbers.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.