Advanced TFormula and TF1 usage

Dear *,

I probably have a strange or crazy problems. But I try to extend my understanding :wink:

Entering the following in cint directly is successful:
TF1 f(“myf”,“x*exp(-x)”,0.10);
TF1 g(“g”,“myf(x)*TMath::BesselJ0(x)”,0,10);
TF1 hTF1(“h”,“g.Integral(0.,x)”,0,10);
TCanvas c(“c”,“c”,800,600);
h.Draw();
c.SaveAs(“func.pdf”);

Doing the same thing as ROOT macro, script, or compiled code fails with
input_line_15:2:118: error: member reference type ‘double’ is not a pointer
Double_t TFormula____id14289597942108301067(Double_t *x){ return ((x[0])*TMath::Exp(-(x[0]))*TMath::BesselJ0(x[0])).Integral(0.,x[0]) ; }
[…]

I mean I understand from the error that TFormula translates the string in direct C/C++ code. And this evaluates to the return value (double), which is not TF1 object, and thus has no Integrate() class member function. And you are fully right: There are dozens of alternatives (which I all tested and find them acceptable, too).

But more interesting for me is, why does it work under cint? Would be there a way that his can be done also as script/binary executable?
If this would work, convolutions like the following would be two lines!
TF1 glcore(“glcore”,"[0]*TMath::Landau(x,[1],[2],true)*TMath::Gaus(x,[3],[4],true)",0,512.);
TF1 gl(“gl”,"[&](double x, double p){glcore.SetParameters([0],[1],[2],x,[3]); return glcore.Integral(x-5[3],x+5[3]);}",0,512.,4);
That would be really cool! :wink:

Is there such a way?
Many thanks in advance! (And sorry, if that question already appeared and was answered somewhere else. A link to there would be very kind from you, then! My internet researches where rather successless so far.)

Cheers, Martin


Please read tips for efficient and successful posting and posting code

_ROOT Version:6.18
_Platform:Debian Buster
_Compiler:GCC 8.3


Hi,

As you pointed out, the example does not work in TFormula when using in a macro, but it works fine when using in the interpreter. Also if housing an interpreted Lambda the outcome is the same, because when the TF1 object g is created in a macro is not visible to the Cling global scope.
I am not sure what is the best way to fix this. However adding this line before creating the TF1 h, fixes the problem:

gInterpreter->ProcessLine("TF1 & g = *( (TF1*) gROOT->GetFunction(\"g\"))" );
TF1 h("h1","g.Integral(0.,x)",0,10);

Lorenzo

Well, that’s interesting! That might be a solution … :wink: Not that simple as I had in mind. But still, I understand it.
Many thanks!

Hi again,

I guess, Lambdas together with std::function is then probably the most direct way. Here the complete example as root script.

#include "TH1D.h"
#include "TCanvas.h"
#include "TF1.h"
void test() {
  TF1 gala("glcore","[0]*TMath::Landau(x,[1],[2],true)*TMath::Gaus(x,[3],[4],true)",-100.,100.);
  std::function<double(double*,double*)> f =
    [&gala](double*x,double*p){
      gala.SetParameters(p[0],p[1],p[2],x[0],p[3]);
      return gala.Integral(x[0]-5.*p[3],x[0]+5.*p[3]);
    };
  TF1 gl("gl",f,0,512.,4);
  gl.SetParameters(1000.,130.,10.,13.);
  TH1D h("h","ADC Channels",512,0.,512.);
  h.FillRandom("gl",10000);
  TCanvas c("c","c",800,600);
  h.Draw(); // <- up to here from sample
  // Fitting now
  gl.SetParNames("norm","MPV_L","sigma_L","sigma_G");
  gl.SetParameters(1000.,100.,20.,20.);
  gl.FixParameter(0,h.GetEntries()*h.GetBinWidth(5));
  gl.SetNpx(200);
  h.Fit("gl","ML");
  c.SaveAs("GLfit.pdf");
}

Btw. as ROOT macro ({…}) the TFormula way also works. But for what I needed, I then anyway had to go with Lambdas.

{
  TF1 gala("glcore","[0]*TMath::Landau(x,[1],[2],true)*TMath::Gaus(x,[3],[4],true)",-100.,100.);
  TF1 gl("gl","[&](double*x, double*p){gala.SetParameters(p[0],p[1],p[2],x[0],p[3]); return gala.Integral(x[0]-5.*p[3],x[0]+5.*p[3]);}",0,512.,4);
  gl.SetParameters(1000.,130.,10.,13.);
  TH1D h("h","ADC Channels",512,0.,512.);
  h.FillRandom("gl",10000);
  TCanvas c("c","c",800,600);
  h.Draw(); // <- up to here from sample
  // Fitting now
  gl.SetParNames("norm","MPV_L","sigma_L","sigma_G");
  gl.SetParameters(1000.,100.,20.,20.);
  gl.FixParameter(0,h.GetEntries()*h.GetBinWidth(5));
  gl.SetNpx(200);
  h.Fit("gl","ML");
  c.SaveAs("GLfit.pdf");
}

As ROOT Macro, that’s acceptable.

Many thanks, once more!
Cheers, Martin

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