42 ClassImp(TF1Convolution);
44 class TF1Convolution_EvalWrapper
51 TF1Convolution_EvalWrapper(TF1 &f1, TF1 &f2, Double_t t) :
56 Double_t operator()(Double_t x)
const
62 return fFunc1->EvalPar(xx,
nullptr) * fFunc2->EvalPar(xx+1,
nullptr);
69 void TF1Convolution::InitializeDataMembers(TF1* function1, TF1* function2, Bool_t useFFT)
73 if (function1->GetNdim() != 1)
74 Error(
"InitializeDataMembers",
"function1 %s is not of dimension 1 ",function1->GetName());
77 fFunction1 = std::unique_ptr<TF1> (
new TF1());
78 function1->Copy(*fFunction1);
81 if (function2->GetNdim() != 1)
82 Error(
"InitializeDataMembers",
"function2 %s is not of dimension 1 ",function2->GetName());
84 fFunction2 = std::unique_ptr<TF1>(
new TF1());
85 function2->Copy(*fFunction2);
87 if (fFunction1.get() ==
nullptr|| fFunction2.get() ==
nullptr)
88 Fatal(
"InitializeDataMembers",
"Invalid functions - Abort");
91 fFunction1->SetBit(TF1::kNotGlobal, kTRUE);
92 fFunction2->SetBit(TF1::kNotGlobal, kTRUE);
95 fFunction1->GetRange(fXmin, fXmax);
96 Double_t range = fXmax - fXmin;
99 fNofParams1 = fFunction1->GetNpar();
100 fNofParams2 = fFunction2->GetNpar();
101 fParams1 = std::vector<Double_t>(fNofParams1);
102 fParams2 = std::vector<Double_t>(fNofParams2);
103 fCstIndex = (fFunction1->GetParNumber(
"Constant") == -1)
105 : fFunction2->GetParNumber(
"Constant");
110 fParNames.reserve( fNofParams1 + fNofParams2);
111 for (
int i=0; i<fNofParams1; i++)
113 fParams1[i] = fFunction1 -> GetParameter(i);
114 fParNames.push_back(fFunction1 -> GetParName(i) );
116 for (
int i=0; i<fNofParams2; i++)
118 fParams2[i] = fFunction2 -> GetParameter(i);
119 if (i != fCstIndex) fParNames.push_back(fFunction2 -> GetParName(i) );
123 fFunction2 -> FixParameter(fCstIndex,1.);
124 fNofParams2 = fNofParams2-1;
125 fParams2.erase(fParams2.begin()+fCstIndex);
132 TF1Convolution::TF1Convolution()
140 TF1Convolution::TF1Convolution(TF1* function1, TF1* function2, Bool_t useFFT)
142 InitializeDataMembers(function1,function2, useFFT);
148 TF1Convolution::TF1Convolution(TF1* function1, TF1* function2, Double_t xmin, Double_t xmax, Bool_t useFFT)
150 InitializeDataMembers(function1, function2,useFFT);
155 Info(
"TF1Convolution",
"Using default range [-inf, inf] for TF1Convolution");
156 SetRange(-TMath::Infinity(), TMath::Infinity());
163 TF1Convolution::TF1Convolution(TString formula, Double_t xmin, Double_t xmax, Bool_t useFFT)
165 TF1::InitStandardFunctions();
167 TObjArray *objarray = formula.Tokenize(
"*");
168 std::vector < TString > stringarray(2);
169 std::vector < TF1* > funcarray(2);
170 for (
int i=0; i<2; i++)
172 stringarray[i] = ((TObjString*)((*objarray)[i])) -> GetString();
173 stringarray[i].ReplaceAll(
" ",
"");
174 funcarray[i] = (TF1*)(gROOT -> GetListOfFunctions() -> FindObject(stringarray[i]));
176 if (funcarray[i] ==
nullptr) {
177 TF1 * f =
new TF1(TString::Format(
"f_conv_%d",i+1),stringarray[i]);
178 if (!f->GetFormula()->IsValid() )
179 Error(
"TF1Convolution",
"Invalid formula : %s",stringarray[i].Data() );
181 fFunction1 = std::unique_ptr<TF1>(f);
183 fFunction2 = std::unique_ptr<TF1>(f);
186 InitializeDataMembers(funcarray[0], funcarray[1],useFFT);
191 Info(
"TF1Convolution",
"Using default range [-inf, inf] for TF1Convolution");
192 SetRange(-TMath::Infinity(), TMath::Infinity());
202 TF1Convolution::TF1Convolution(TString formula1, TString formula2, Double_t xmin, Double_t xmax, Bool_t useFFT)
204 TF1::InitStandardFunctions();
205 (TString)formula1.ReplaceAll(
" ",
"");
206 (TString)formula2.ReplaceAll(
" ",
"");
207 TF1* f1 = (TF1*)(gROOT -> GetListOfFunctions() -> FindObject(formula1));
208 TF1* f2 = (TF1*)(gROOT -> GetListOfFunctions() -> FindObject(formula2));
211 fFunction1 = std::unique_ptr<TF1>(
new TF1(
"f_conv_1", formula1));
212 if (!fFunction1->GetFormula()->IsValid() )
213 Error(
"TF1Convolution",
"Invalid formula for : %s",formula1.Data() );
216 fFunction2 = std::unique_ptr<TF1>(
new TF1(
"f_conv_1", formula2));
217 if (!fFunction2->GetFormula()->IsValid() )
218 Error(
"TF1Convolution",
"Invalid formula for : %s",formula2.Data() );
221 InitializeDataMembers(f1, f2,useFFT);
226 Info(
"TF1Convolution",
"Using default range [-inf, inf] for TF1Convolution");
227 SetRange(-TMath::Infinity(), TMath::Infinity());
234 TF1Convolution::TF1Convolution(
const TF1Convolution &conv)
236 conv.Copy((TObject &)*
this);
242 TF1Convolution &TF1Convolution::operator=(
const TF1Convolution &rhs)
252 void TF1Convolution::MakeFFTConv()
255 Info(
"MakeFFTConv",
"Making FFT convolution using %d points in range [%g,%g]",fNofPoints,fXmin,fXmax);
257 std::vector < Double_t > x (fNofPoints);
258 std::vector < Double_t > in1(fNofPoints);
259 std::vector < Double_t > in2(fNofPoints);
261 TVirtualFFT *fft1 = TVirtualFFT::FFT(1, &fNofPoints,
"R2C K");
262 TVirtualFFT *fft2 = TVirtualFFT::FFT(1, &fNofPoints,
"R2C K");
263 if (fft1 ==
nullptr || fft2 ==
nullptr) {
264 Warning(
"MakeFFTConv",
"Cannot use FFT, probably FFTW package is not available. Switch to numerical convolution");
270 Double_t shift2 = 0.5*(fXmin+fXmax);
272 for (
int i=0; i<fNofPoints; i++)
274 x[i] = fXmin + (fXmax-fXmin)/(fNofPoints-1)*i;
276 in1[i] = fFunction1 -> EvalPar( &x[i],
nullptr);
277 in2[i] = fFunction2 -> EvalPar( &x2,
nullptr);
278 fft1 -> SetPoint(i, in1[i]);
279 fft2 -> SetPoint(i, in2[i]);
286 TVirtualFFT *fftinverse = TVirtualFFT::FFT(1, &fNofPoints,
"C2R K");
287 Double_t re1, re2, im1, im2, out_re, out_im;
289 for (
int i=0;i<=fNofPoints/2.;i++)
291 fft1 -> GetPointComplex(i,re1,im1);
292 fft2 -> GetPointComplex(i,re2,im2);
293 out_re = re1*re2 - im1*im2;
294 out_im = re1*im2 + re2*im1;
295 fftinverse -> SetPoint(i, out_re, out_im);
297 fftinverse -> Transform();
301 fGraphConv = std::unique_ptr<TGraph>(
new TGraph(fNofPoints));
303 for (
int i=0;i<fNofPoints;i++)
306 int j = i + fNofPoints/2;
307 if (j >= fNofPoints) j -= fNofPoints;
309 fGraphConv->SetPoint(i, x[i], fftinverse->GetPointReal(j)*(fXmax-fXmin)/(fNofPoints*fNofPoints) );
311 fGraphConv->SetBit(TGraph::kIsSortedX);
322 Double_t TF1Convolution::EvalFFTConv(Double_t t)
324 if (!fFlagGraph) MakeFFTConv();
327 return fGraphConv -> Eval(t);
330 return EvalNumConv(t);
337 Double_t TF1Convolution::EvalNumConv(Double_t t)
339 TF1Convolution_EvalWrapper fconv( *fFunction1, *fFunction2, t);
342 ROOT::Math::IntegratorOneDim integrator(fconv, ROOT::Math::IntegratorOneDimOptions::DefaultIntegratorType(), 1e-9, 1e-9);
343 if (fXmin != - TMath::Infinity() && fXmax != TMath::Infinity() )
344 result = integrator.Integral(fXmin, fXmax);
345 else if (fXmin == - TMath::Infinity() && fXmax != TMath::Infinity() )
346 result = integrator.IntegralLow(fXmax);
347 else if (fXmin != - TMath::Infinity() && fXmax == TMath::Infinity() )
348 result = integrator.IntegralUp(fXmin);
349 else if (fXmin == - TMath::Infinity() && fXmax == TMath::Infinity() )
350 result = integrator.Integral();
358 Double_t TF1Convolution::operator()(
const Double_t *x,
const Double_t *p)
360 if (p!=0) TF1Convolution::SetParameters(p);
362 Double_t result = 0.;
364 result = EvalFFTConv(x[0]);
366 result = EvalNumConv(x[0]);
372 void TF1Convolution::SetNofPointsFFT(Int_t n)
376 if (fGraphConv) fGraphConv -> Set(fNofPoints);
382 void TF1Convolution::SetParameters(
const Double_t *params)
384 bool equalParams =
true;
385 for (
int i=0; i<fNofParams1; i++) {
386 fFunction1->SetParameter(i, params[i]);
387 equalParams &= (fParams1[i] == params[i]);
388 fParams1[i] = params[i];
393 if (fCstIndex!=-1) offset = 1;
394 Int_t totalnofparams = fNofParams1+fNofParams2+offset;
395 for (
int i=fNofParams1; i<totalnofparams; i++) {
402 fFunction2->SetParameter(k, params[i - offset2]);
403 equalParams &= (fParams2[k - offset2] == params[i - offset2]);
404 fParams2[k - offset2] = params[i - offset2];
408 if (!equalParams) fFlagGraph =
false;
413 void TF1Convolution::SetParameters(Double_t p0, Double_t p1, Double_t p2, Double_t p3,
414 Double_t p4, Double_t p5, Double_t p6, Double_t p7)
416 Double_t params[]={p0,p1,p2,p3,p4,p5,p6,p7};
417 TF1Convolution::SetParameters(params);
422 void TF1Convolution::SetExtraRange(Double_t percentage)
424 if (percentage<0)
return;
425 double range = fXmax = fXmin;
426 fXmin -= percentage * range;
427 fXmax += percentage * range;
433 void TF1Convolution::SetRange(Double_t a, Double_t b)
436 Warning(
"SetRange",
"Invalid range: %f >= %f", a, b);
442 if (fFlagFFT && ( a==-TMath::Infinity() || b==TMath::Infinity() ) )
444 Warning(
"TF1Convolution::SetRange()",
"In FFT mode, range can not be infinite. Infinity has been replaced by range of first function plus a bufferzone to avoid spillover.");
445 if (a ==-TMath::Infinity()) fXmin = fFunction1 -> GetXmin();
446 if ( b== TMath::Infinity()) fXmax = fFunction1 -> GetXmax();
455 void TF1Convolution::GetRange(Double_t &a, Double_t &b)
const
464 void TF1Convolution::Update()
466 fFunction1->Update();
467 fFunction2->Update();
472 void TF1Convolution::Copy(TObject &obj)
const
475 ((TF1Convolution &)obj).fXmin = fXmin;
476 ((TF1Convolution &)obj).fXmax = fXmax;
477 ((TF1Convolution &)obj).fNofParams1 = fNofParams1;
478 ((TF1Convolution &)obj).fNofParams2 = fNofParams2;
479 ((TF1Convolution &)obj).fCstIndex = fCstIndex;
480 ((TF1Convolution &)obj).fNofPoints = fNofPoints;
481 ((TF1Convolution &)obj).fFlagFFT = fFlagFFT;
482 ((TF1Convolution &)obj).fFlagGraph =
false;
485 ((TF1Convolution &)obj).fParams1 = fParams1;
486 ((TF1Convolution &)obj).fParams2 = fParams2;
487 ((TF1Convolution &)obj).fParNames = fParNames;
490 ((TF1Convolution &)obj).fFunction1 = std::unique_ptr<TF1>((TF1 *)
new TF1() );
491 ((TF1Convolution &)obj).fFunction2 = std::unique_ptr<TF1>((TF1 *)
new TF1() );
492 fFunction1->Copy(*(((TF1Convolution &)obj).fFunction1 ) );
493 fFunction2->Copy(*(((TF1Convolution &)obj).fFunction2 ) );