ROOT logo
//-----------------------------------------------------------------------
//
//	Convoluted Landau and Gaussian Fitting Function
//         (using ROOT's Landau and Gauss functions)
//
//  Based on a Fortran code by R.Fruehwirth (fruhwirth@hephy.oeaw.ac.at)
//  Adapted for C++/ROOT by H.Pernegger (Heinz.Pernegger@cern.ch) and
//   Markus Friedl (Markus.Friedl@cern.ch)
//
//  to execute this example, do:
//  root > .x langaus.C
// or
//  root > .x langaus.C++
//
//-----------------------------------------------------------------------

#include "TH1.h"
#include "TF1.h"
#include "TROOT.h"
#include "TStyle.h"
#include "TMath.h"

Double_t langaufun(Double_t *x, Double_t *par) {

   //Fit parameters:
   //par[0]=Width (scale) parameter of Landau density
   //par[1]=Most Probable (MP, location) parameter of Landau density
   //par[2]=Total area (integral -inf to inf, normalization constant)
   //par[3]=Width (sigma) of convoluted Gaussian function
   //
   //In the Landau distribution (represented by the CERNLIB approximation), 
   //the maximum is located at x=-0.22278298 with the location parameter=0.
   //This shift is corrected within this function, so that the actual
   //maximum is identical to the MP parameter.

      // Numeric constants
      Double_t invsq2pi = 0.3989422804014;   // (2 pi)^(-1/2)
      Double_t mpshift  = -0.22278298;       // Landau maximum location

      // Control constants
      Double_t np = 100.0;      // number of convolution steps
      Double_t sc =   5.0;      // convolution extends to +-sc Gaussian sigmas

      // Variables
      Double_t xx;
      Double_t mpc;
      Double_t fland;
      Double_t sum = 0.0;
      Double_t xlow,xupp;
      Double_t step;
      Double_t i;


      // MP shift correction
      mpc = par[1] - mpshift * par[0]; 

      // Range of convolution integral
      xlow = x[0] - sc * par[3];
      xupp = x[0] + sc * par[3];

      step = (xupp-xlow) / np;

      // Convolution integral of Landau and Gaussian by sum
      for(i=1.0; i<=np/2; i++) {
         xx = xlow + (i-.5) * step;
         fland = TMath::Landau(xx,mpc,par[0]) / par[0];
         sum += fland * TMath::Gaus(x[0],xx,par[3]);

         xx = xupp - (i-.5) * step;
         fland = TMath::Landau(xx,mpc,par[0]) / par[0];
         sum += fland * TMath::Gaus(x[0],xx,par[3]);
      }

      return (par[2] * step * sum * invsq2pi / par[3]);
}



TF1 *langaufit(TH1F *his, Double_t *fitrange, Double_t *startvalues, Double_t *parlimitslo, Double_t *parlimitshi, Double_t *fitparams, Double_t *fiterrors, Double_t *ChiSqr, Int_t *NDF)
{
   // Once again, here are the Landau * Gaussian parameters:
   //   par[0]=Width (scale) parameter of Landau density
   //   par[1]=Most Probable (MP, location) parameter of Landau density
   //   par[2]=Total area (integral -inf to inf, normalization constant)
   //   par[3]=Width (sigma) of convoluted Gaussian function
   //
   // Variables for langaufit call:
   //   his             histogram to fit
   //   fitrange[2]     lo and hi boundaries of fit range
   //   startvalues[4]  reasonable start values for the fit
   //   parlimitslo[4]  lower parameter limits
   //   parlimitshi[4]  upper parameter limits
   //   fitparams[4]    returns the final fit parameters
   //   fiterrors[4]    returns the final fit errors
   //   ChiSqr          returns the chi square
   //   NDF             returns ndf

   Int_t i;
   Char_t FunName[100];

   sprintf(FunName,"Fitfcn_%s",his->GetName());

   TF1 *ffitold = (TF1*)gROOT->GetListOfFunctions()->FindObject(FunName);
   if (ffitold) delete ffitold;

   TF1 *ffit = new TF1(FunName,langaufun,fitrange[0],fitrange[1],4);
   ffit->SetParameters(startvalues);
   ffit->SetParNames("Width","MP","Area","GSigma");
   
   for (i=0; i<4; i++) {
      ffit->SetParLimits(i, parlimitslo[i], parlimitshi[i]);
   }

   his->Fit(FunName,"RB0");   // fit within specified range, use ParLimits, do not plot

   ffit->GetParameters(fitparams);    // obtain fit parameters
   for (i=0; i<4; i++) {
      fiterrors[i] = ffit->GetParError(i);     // obtain fit parameter errors
   }
   ChiSqr[0] = ffit->GetChisquare();  // obtain chi^2
   NDF[0] = ffit->GetNDF();           // obtain ndf

   return (ffit);              // return fit function

}


Int_t langaupro(Double_t *params, Double_t &maxx, Double_t &FWHM) {

   // Seaches for the location (x value) at the maximum of the 
   // Landau-Gaussian convolute and its full width at half-maximum.
   //
   // The search is probably not very efficient, but it's a first try.

   Double_t p,x,fy,fxr,fxl;
   Double_t step;
   Double_t l,lold;
   Int_t i = 0;
   Int_t MAXCALLS = 10000;


   // Search for maximum

   p = params[1] - 0.1 * params[0];
   step = 0.05 * params[0];
   lold = -2.0;
   l    = -1.0;


   while ( (l != lold) && (i < MAXCALLS) ) {
      i++;

      lold = l;
      x = p + step;
      l = langaufun(&x,params);
 
      if (l < lold)
         step = -step/10;
 
      p += step;
   }

   if (i == MAXCALLS)
      return (-1);

   maxx = x;

   fy = l/2;


   // Search for right x location of fy

   p = maxx + params[0];
   step = params[0];
   lold = -2.0;
   l    = -1e300;
   i    = 0;


   while ( (l != lold) && (i < MAXCALLS) ) {
      i++;

      lold = l;
      x = p + step;
      l = TMath::Abs(langaufun(&x,params) - fy);
 
      if (l > lold)
         step = -step/10;
 
      p += step;
   }

   if (i == MAXCALLS)
      return (-2);

   fxr = x;


   // Search for left x location of fy

   p = maxx - 0.5 * params[0];
   step = -params[0];
   lold = -2.0;
   l    = -1e300;
   i    = 0;

   while ( (l != lold) && (i < MAXCALLS) ) {
      i++;

      lold = l;
      x = p + step;
      l = TMath::Abs(langaufun(&x,params) - fy);
 
      if (l > lold)
         step = -step/10;
 
      p += step;
   }

   if (i == MAXCALLS)
      return (-3);


   fxl = x;

   FWHM = fxr - fxl;
   return (0);
}

void langaus() {
   // Fill Histogram
   Int_t data[100] = {0,0,0,0,0,0,2,6,11,18,18,55,90,141,255,323,454,563,681,
                    737,821,796,832,720,637,558,519,460,357,291,279,241,212,
                    153,164,139,106,95,91,76,80,80,59,58,51,30,49,23,35,28,23,
                    22,27,27,24,20,16,17,14,20,12,12,13,10,17,7,6,12,6,12,4,
                    9,9,10,3,4,5,2,4,1,5,5,1,7,1,6,3,3,3,4,5,4,4,2,2,7,2,4};
   TH1F *hSNR = new TH1F("snr","Signal-to-noise",400,0,400);

   for (Int_t i=0; i<100; i++) hSNR->Fill(i,data[i]);

   // Fitting SNR histo
   printf("Fitting...\n");

   // Setting fit range and start values
   Double_t fr[2];
   Double_t sv[4], pllo[4], plhi[4], fp[4], fpe[4];
   fr[0]=0.3*hSNR->GetMean();
   fr[1]=3.0*hSNR->GetMean();

   pllo[0]=0.5; pllo[1]=5.0; pllo[2]=1.0; pllo[3]=0.4;
   plhi[0]=5.0; plhi[1]=50.0; plhi[2]=1000000.0; plhi[3]=5.0;
   sv[0]=1.8; sv[1]=20.0; sv[2]=50000.0; sv[3]=3.0;

   Double_t chisqr;
   Int_t    ndf;
   TF1 *fitsnr = langaufit(hSNR,fr,sv,pllo,plhi,fp,fpe,&chisqr,&ndf);
   
   Double_t SNRPeak, SNRFWHM;
   langaupro(fp,SNRPeak,SNRFWHM);

   printf("Fitting done\nPlotting results...\n");

   // Global style settings
   gStyle->SetOptStat(1111);
   gStyle->SetOptFit(111);
   gStyle->SetLabelSize(0.03,"x");
   gStyle->SetLabelSize(0.03,"y");

   hSNR->GetXaxis()->SetRange(0,70);
   hSNR->Draw();
   fitsnr->Draw("lsame");
}

 langaus.C:1
 langaus.C:2
 langaus.C:3
 langaus.C:4
 langaus.C:5
 langaus.C:6
 langaus.C:7
 langaus.C:8
 langaus.C:9
 langaus.C:10
 langaus.C:11
 langaus.C:12
 langaus.C:13
 langaus.C:14
 langaus.C:15
 langaus.C:16
 langaus.C:17
 langaus.C:18
 langaus.C:19
 langaus.C:20
 langaus.C:21
 langaus.C:22
 langaus.C:23
 langaus.C:24
 langaus.C:25
 langaus.C:26
 langaus.C:27
 langaus.C:28
 langaus.C:29
 langaus.C:30
 langaus.C:31
 langaus.C:32
 langaus.C:33
 langaus.C:34
 langaus.C:35
 langaus.C:36
 langaus.C:37
 langaus.C:38
 langaus.C:39
 langaus.C:40
 langaus.C:41
 langaus.C:42
 langaus.C:43
 langaus.C:44
 langaus.C:45
 langaus.C:46
 langaus.C:47
 langaus.C:48
 langaus.C:49
 langaus.C:50
 langaus.C:51
 langaus.C:52
 langaus.C:53
 langaus.C:54
 langaus.C:55
 langaus.C:56
 langaus.C:57
 langaus.C:58
 langaus.C:59
 langaus.C:60
 langaus.C:61
 langaus.C:62
 langaus.C:63
 langaus.C:64
 langaus.C:65
 langaus.C:66
 langaus.C:67
 langaus.C:68
 langaus.C:69
 langaus.C:70
 langaus.C:71
 langaus.C:72
 langaus.C:73
 langaus.C:74
 langaus.C:75
 langaus.C:76
 langaus.C:77
 langaus.C:78
 langaus.C:79
 langaus.C:80
 langaus.C:81
 langaus.C:82
 langaus.C:83
 langaus.C:84
 langaus.C:85
 langaus.C:86
 langaus.C:87
 langaus.C:88
 langaus.C:89
 langaus.C:90
 langaus.C:91
 langaus.C:92
 langaus.C:93
 langaus.C:94
 langaus.C:95
 langaus.C:96
 langaus.C:97
 langaus.C:98
 langaus.C:99
 langaus.C:100
 langaus.C:101
 langaus.C:102
 langaus.C:103
 langaus.C:104
 langaus.C:105
 langaus.C:106
 langaus.C:107
 langaus.C:108
 langaus.C:109
 langaus.C:110
 langaus.C:111
 langaus.C:112
 langaus.C:113
 langaus.C:114
 langaus.C:115
 langaus.C:116
 langaus.C:117
 langaus.C:118
 langaus.C:119
 langaus.C:120
 langaus.C:121
 langaus.C:122
 langaus.C:123
 langaus.C:124
 langaus.C:125
 langaus.C:126
 langaus.C:127
 langaus.C:128
 langaus.C:129
 langaus.C:130
 langaus.C:131
 langaus.C:132
 langaus.C:133
 langaus.C:134
 langaus.C:135
 langaus.C:136
 langaus.C:137
 langaus.C:138
 langaus.C:139
 langaus.C:140
 langaus.C:141
 langaus.C:142
 langaus.C:143
 langaus.C:144
 langaus.C:145
 langaus.C:146
 langaus.C:147
 langaus.C:148
 langaus.C:149
 langaus.C:150
 langaus.C:151
 langaus.C:152
 langaus.C:153
 langaus.C:154
 langaus.C:155
 langaus.C:156
 langaus.C:157
 langaus.C:158
 langaus.C:159
 langaus.C:160
 langaus.C:161
 langaus.C:162
 langaus.C:163
 langaus.C:164
 langaus.C:165
 langaus.C:166
 langaus.C:167
 langaus.C:168
 langaus.C:169
 langaus.C:170
 langaus.C:171
 langaus.C:172
 langaus.C:173
 langaus.C:174
 langaus.C:175
 langaus.C:176
 langaus.C:177
 langaus.C:178
 langaus.C:179
 langaus.C:180
 langaus.C:181
 langaus.C:182
 langaus.C:183
 langaus.C:184
 langaus.C:185
 langaus.C:186
 langaus.C:187
 langaus.C:188
 langaus.C:189
 langaus.C:190
 langaus.C:191
 langaus.C:192
 langaus.C:193
 langaus.C:194
 langaus.C:195
 langaus.C:196
 langaus.C:197
 langaus.C:198
 langaus.C:199
 langaus.C:200
 langaus.C:201
 langaus.C:202
 langaus.C:203
 langaus.C:204
 langaus.C:205
 langaus.C:206
 langaus.C:207
 langaus.C:208
 langaus.C:209
 langaus.C:210
 langaus.C:211
 langaus.C:212
 langaus.C:213
 langaus.C:214
 langaus.C:215
 langaus.C:216
 langaus.C:217
 langaus.C:218
 langaus.C:219
 langaus.C:220
 langaus.C:221
 langaus.C:222
 langaus.C:223
 langaus.C:224
 langaus.C:225
 langaus.C:226
 langaus.C:227
 langaus.C:228
 langaus.C:229
 langaus.C:230
 langaus.C:231
 langaus.C:232
 langaus.C:233
 langaus.C:234
 langaus.C:235
 langaus.C:236
 langaus.C:237
 langaus.C:238
 langaus.C:239
 langaus.C:240
 langaus.C:241
 langaus.C:242
 langaus.C:243
 langaus.C:244
 langaus.C:245
 langaus.C:246
 langaus.C:247
 langaus.C:248
 langaus.C:249
 langaus.C:250
 langaus.C:251
 langaus.C:252
 langaus.C:253
 langaus.C:254
 langaus.C:255
 langaus.C:256
 langaus.C:257
 langaus.C:258
 langaus.C:259
 langaus.C:260
 langaus.C:261
 langaus.C:262
 langaus.C:263
 langaus.C:264
 langaus.C:265
 langaus.C:266
 langaus.C:267
 langaus.C:268
 langaus.C:269
 langaus.C:270
 langaus.C:271
 langaus.C:272
 langaus.C:273
 langaus.C:274