GammaWare  Head Version for release 0.9
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
PeakFitter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2004-2006 by Olivier Stezowski & Christophe Theisen *
3  * stezow(AT)ipnl.in2p3.fr, christophe.theisen(AT)cea.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
20 
23 #ifndef GW_PEAKFITTER_H
24 #include "PeakFitter.h"
25 #endif
26 #ifndef GW_CLICKCOLLECTOR_H
27 #include "ClickCollector.h"
28 #endif
29 #ifndef ROOT_TMath_H
30 #include "TMath.h"
31 #endif
32 #ifndef ROOT_TAxis_H
33 #include "TAxis.h"
34 #endif
35 #ifndef ROOT_TLine_H
36 #include "TLine.h"
37 #endif
38 #ifndef ROOT_TF1_H
39 #include "TF1.h"
40 #endif
41 #ifndef ROOT_TCanvas_H
42 #include "TCanvas.h"
43 #endif
44 #ifndef ROOT_TVirtualFitter_H
45 #include "TVirtualFitter.h"
46 #endif
47 #ifndef ROOT_TObject_H
48 #include "TObject.h"
49 #endif
50 #ifndef ROOT_TQObject_H
51 #include "TQObject.h"
52 #endif
53 
54 
55 #include <iostream>
56 #include <fstream>
57 
58 using namespace std;
59 using namespace GwD;
60 
61 // ROOT dictionnary
63 
64 Double_t SkewedGaussian(Double_t *x, Double_t *par){ //SkewedGaussian function (See Radford WebSite for details)
65  return(par[0]*TMath::Exp(-0.5*TMath::Power(((x[0]-par[1])/par[2]),2)) +
66  par[3]*TMath::Exp((x[0]-par[1])/par[4])*TMath::Erfc(((x[0]-par[1])/(TMath::Sqrt(2.0)*par[2])) +
67  (par[2]/(TMath::Sqrt(2.0)*par[4]))) + par[5]*TMath::Erfc((x[0]-par[1])/(TMath::Sqrt(2.0)*par[2])));
68 }
69 
70 PeakFitter::PeakFitter() : fPeaks(0), fType(kGauss)//Defaut Constructor
71 {
72  //fGaussian = new TF1("Gaussian",Gaussian);
73  //fGaussian->SetParNames("Constant","Mean","Sigma");
74  //fGaussian->SetLineColor(2);
75  //fSkewed = new TF1("Skewed",SkewedGaussian);
76  //fSkewed->SetParNames("ConstantGaus","Mean","Sigma","ConstantSkewed","Beta","ConstantStep");
77  //fSkewed->SetLineColor(3);
78 
79 
80  fMainFrame = new TGMainFrame(0,10,10,kMainFrame | kVerticalFrame);
81  fMainFrame->SetLayoutBroken(kTRUE);
82 
83  fGroupFrame1 = new TGGroupFrame(fMainFrame,"PeakFitter");
84  fGroupFrame1->SetLayoutBroken(kTRUE);
85 
86  // button "CollectOn"
87  fTextButtonCollectOn = new TGTextButton(fGroupFrame1,"CollectOn");
88  fTextButtonCollectOn->SetTextJustify(36);
89  fGroupFrame1->AddFrame(fTextButtonCollectOn, new TGLayoutHints(kLHintsLeft | kLHintsTop,2,2,2,2));
90  fTextButtonCollectOn->MoveResize(10,30,100,40);
91 
92  // button "CollectOff"
93  fTextButtonCollectOff = new TGTextButton(fGroupFrame1,"CollectOff");
94  fTextButtonCollectOff->SetTextJustify(36);
95  fGroupFrame1->AddFrame(fTextButtonCollectOff, new TGLayoutHints(kLHintsLeft | kLHintsTop,2,2,2,2));
96  fTextButtonCollectOff->MoveResize(120,30,100,40);
97 
98  // button "DoFit"
99  fTextButtonDoFit = new TGTextButton(fGroupFrame1,"DoFit");
100  fTextButtonDoFit->SetTextJustify(36);
101  fGroupFrame1->AddFrame(fTextButtonDoFit, new TGLayoutHints(kLHintsLeft | kLHintsTop,2,2,2,2));
102  fTextButtonDoFit->MoveResize(10,80,100,40);
103 
104  // Type combo box
105  fComboBoxFunctionType = new TGComboBox(fGroupFrame1,"Function Type");
106  fComboBoxFunctionType->AddEntry("Gaussian",0);
107  fComboBoxFunctionType->AddEntry("Skewed",1);
108  fComboBoxFunctionType->Select(0);
109  fGroupFrame1->AddFrame(fComboBoxFunctionType, new TGLayoutHints(kLHintsLeft | kLHintsTop,2,2,2,2));
110  fComboBoxFunctionType->MoveResize(120,80,100,40);
111 
112  // button "ClearMarkers"
113  fTextButtonClearMarkers = new TGTextButton(fGroupFrame1,"ClearMarkers");
114  fTextButtonClearMarkers->SetTextJustify(36);
115  fGroupFrame1->AddFrame(fTextButtonClearMarkers, new TGLayoutHints(kLHintsLeft | kLHintsTop,2,2,2,2));
116  fTextButtonClearMarkers->MoveResize(10,130,100,40);
117 
118  // button "ClearLastMarker"
119  fTextButtonClearLastMarker = new TGTextButton(fGroupFrame1,"ClearLastMarker");
120  fTextButtonClearLastMarker->SetTextJustify(36);
121  fGroupFrame1->AddFrame(fTextButtonClearLastMarker, new TGLayoutHints(kLHintsLeft | kLHintsTop,2,2,2,2));
122  fTextButtonClearLastMarker->MoveResize(120,130,100,40);
123 
124 
125  //Gestion des boutons
126  fTextButtonCollectOn->Connect("Clicked()","Gw::PeakFitter",this,"CollectOn()");
127  fTextButtonCollectOff->Connect("Clicked()","Gw::PeakFitter",this,"CollectOff()");
128  fTextButtonDoFit->Connect("Clicked()","Gw::PeakFitter",this,"DoFit1(=1.0)");
129  fTextButtonClearMarkers->Connect("Clicked()","Gw::PeakFitter",this,"ClearMarkers()");
130  fTextButtonClearLastMarker->Connect("Clicked()","Gw::PeakFitter",this,"ClearLastMarker()");
131  fComboBoxFunctionType->Connect("Selected(Int_t)","Gw::PeakFitter",this,"SetFunctionType(Int_t)");
132 
133 
134  fGroupFrame1->SetLayoutManager(new TGVerticalLayout(fGroupFrame1));
135  fMainFrame->AddFrame(fGroupFrame1, new TGLayoutHints(kLHintsLeft | kLHintsTop,2,2,2,2));
136  fGroupFrame1->MoveResize(10,10,250,180);
137 
138  fMainFrame->SetMWMHints(kMWMDecorAll,kMWMFuncAll,kMWMInputModeless);
139  fMainFrame->MapSubwindows();
140  fMainFrame->MapWindow();
141  fMainFrame->Resize(270,200);
142 }
143 
144 PeakFitter::~PeakFitter(){ //Destructor
145  delete fMainFrame;
146  delete fGroupFrame1;
147  delete fTextButtonCollectOn;
148  delete fTextButtonDoFit;
151  delete fComboBoxFunctionType;
152 }
153 
155 {
156  if ( TVirtualPad::Pad() ) {
157  TCanvas *c = TVirtualPad::Pad()->GetCanvas(); ClickCollector *thecollector = ClickCollector::TheCollector();
158  c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)","Gw::ClickCollector",thecollector,"DoCollect(Int_t,Int_t,Int_t,TObject*)");
159  cout << " - Start collecting clicks in " << c->GetName() << endl ;
160 
161  thecollector->SetMode();
162  }
163  else
164  cout << " - Cannot collect clicks, there is no current pad !!! " << endl ;
165 
166 }
167 
169 {
170  if ( TVirtualPad::Pad() ) {
171  TCanvas *c = TVirtualPad::Pad()->GetCanvas(); ClickCollector *thecollector = ClickCollector::TheCollector();
172  thecollector->SetMode(false);
173  cout << " - Stop collecting clicks in " << c->GetName() << endl ;
174  }
175 }
176 
177 
179 {
180  TObject *obj; if ( TVirtualPad::Pad() == NULL ) return;
181 
182  TIter next(TVirtualPad::Pad()->GetListOfPrimitives());
183  while ( (obj = next()) ) { // look for markers
184  if ( obj->InheritsFrom("TMarker") ) { delete obj; }
185  }
186  TVirtualPad::Pad()->Update();
187 }
188 
190 {
191  TObject *obj; if ( TVirtualPad::Pad() == NULL ) return;
192 
193  TIter next(TVirtualPad::Pad()->GetListOfPrimitives(),kIterBackward);
194  while ( (obj = next()) ) { // look for markers
195  if ( obj->InheritsFrom("TMarker") ) { delete obj; break; }
196  }
197  TVirtualPad::Pad()->Update();
198 }
199 
200 
206 void PeakFitter::DoFit1(Float_t sigma)
207 {
208  Float_t beta = 5.;
209  const Int_t MAXMARKERS = 50 ; TVirtualFitter::Fitter(0,3*MAXMARKERS); //to get a maximum of 150 parameters
210 
211  Int_t i, nbmarkers, nbgauss, ind[MAXMARKERS];
212  Float_t x[MAXMARKERS], y[MAXMARKERS], /*xgauss[MAXMARKERS], ygauss[MAXMARKERS],*/ xlow, xhigh; Double_t par[3*MAXMARKERS];
213 
214  TObject *obj;
215 
216  if ( TVirtualPad::Pad() == NULL ) return;
217 
218  TH1 *hist;
219  TIter next(TVirtualPad::Pad()->GetListOfPrimitives());
220 
221  hist = NULL; nbmarkers = 0;
222  while ( (obj = next()) ) { // look for an histogram and for markers
223  if ( obj->InheritsFrom("TMarker") ) {
224  x[nbmarkers] = ((TMarker *)obj)->GetX();
225  y[nbmarkers++] = ((TMarker *)obj)->GetY();
226  }
227  if ( obj->InheritsFrom("TH1") && !obj->InheritsFrom("TH2") ) { hist = (TH1 *)obj; }
228  }
229  if ( hist == NULL || nbmarkers < 3 ) {
230  printf("There is no histograms or enough clicks in the current pad to realise a graphical fit \n"); return; }
231 
232 
233  // first one and last one are for background
234  TMath::Sort(nbmarkers,x,ind,false); xlow = x[ind[0]]; xhigh = x[ind[nbmarkers-1]];
235 
236  // histograms used to fit
237  TH1 *lochist = (TH1 *)hist->Clone("fitter"); lochist->Reset("ICE");
238 
239  // to get the backgound
240  Int_t first_bin, last_bin; Stat_t first_bin_c, last_bin_c, bin_c;
241 
242  first_bin = hist->FindBin( xlow );
243  last_bin = hist->FindBin( xhigh );
244  first_bin_c = hist->GetBinContent(first_bin); last_bin_c = hist->GetBinContent(last_bin);
245 
246  // determine the linear function for the background
247  TF1 *fbg;
248  if ( ( fbg = (TF1 *)gROOT->GetListOfFunctions()->FindObject("Background") ) ) { delete fbg; }
249 
250  fbg = new TF1("Background","pol1",xlow,xhigh);
251  fbg->SetParameters(first_bin_c-xlow*(last_bin_c-first_bin_c)/(xhigh-xlow),(last_bin_c-first_bin_c)/(xhigh-xlow));
252 
253  fbg->SetLineColor(30); fbg->SetLineWidth(3); fbg->SetLineStyle(1); fbg->Draw("same");
254 
255  // fill the histogram that is used to fit
256  for ( i = first_bin; i < last_bin ; i++ ) {
257  bin_c = hist->GetBinContent(i) -
258  ( Float_t(i-first_bin)*(last_bin_c-first_bin_c)/(last_bin-first_bin) + first_bin_c ) ;
259  lochist->SetBinContent(i,bin_c);
260  }
261  // now the function used to fit is created
262  char fname[500]; TString ffit, fdisplay = "pol1(0)";
263 
264  nbgauss = 0;
265  for ( i = 1; i < nbmarkers - 1; i++ ) {
266 
267  if ( y[ind[i]] < fbg->Eval(x[ind[i]]) ) { // background too high cannot add a gaussian at this position
268  printf("background too high at position %.1f \n",x[ind[i]]); continue;
269  }
270 
271  if (fType == kGauss) {
272  // add a new gaussian and init parameters
273  par[3*nbgauss] = y[ind[i]] - fbg->Eval(x[ind[i]]);
274  par[3*nbgauss+1] = x[ind[i]];
275  par[3*nbgauss+2] = sigma;
276  sprintf(fname,"gaus(%d)",nbgauss*3); ffit += "+"; ffit += fname;
277  sprintf(fname,"gaus(%d)",2+nbgauss*3); fdisplay += "+"; fdisplay += fname;
278  }
279 
280  if (fType == kSkewed) {
281  // add a new SkewedGaussian and init parameters
282  par[6*nbgauss] = y[ind[i]] - fbg->Eval(x[ind[i]]);
283  par[6*nbgauss+1] = x[ind[i]];
284  par[6*nbgauss+2] = sigma;
285  par[6*nbgauss+3] = (y[ind[i]] - fbg->Eval(x[ind[i]]))/10.;
286  par[6*nbgauss+4] = beta;
287  par[6*nbgauss+5] = 0.;
288 
289  sprintf(fname, "[%d]*TMath::Exp(-0.5*TMath::Power(((x-[%d])/[%d]),2)) + [%d]*TMath::Exp((x-[%d])/[%d])*TMath::Erfc(((x-[%d])/(TMath::Sqrt(2.0)*[%d])) + ([%d]/(TMath::Sqrt(2.0)*[%d]))) + [%d]*TMath::Erfc((x-[%d])/(TMath::Sqrt(2.0)*[%d]))",6*nbgauss,6*nbgauss+1,6*nbgauss+2,6*nbgauss+3,6*nbgauss+1,6*nbgauss+4,6*nbgauss+1,6*nbgauss+2,6*nbgauss+2,6*nbgauss+4,6*nbgauss+5,6*nbgauss+1,6*nbgauss+2);
290 
291  ffit += "+"; ffit += fname;
292 
293  sprintf(fname, "[%d]*TMath::Exp(-0.5*TMath::Power(((x-[%d])/[%d]),2)) + [%d]*TMath::Exp((x-[%d])/[%d])*TMath::Erfc(((x-[%d])/(TMath::Sqrt(2.0)*[%d])) + ([%d]/(TMath::Sqrt(2.0)*[%d]))) + [%d]*TMath::Erfc((x-[%d])/(TMath::Sqrt(2.0)*[%d]))",2+6*nbgauss,2+6*nbgauss+1,2+6*nbgauss+2,2+6*nbgauss+3,2+6*nbgauss+1,2+6*nbgauss+4,2+6*nbgauss+1,2+6*nbgauss+2,2+6*nbgauss+2,2+6*nbgauss+4,2+6*nbgauss+5,2+6*nbgauss+1,2+6*nbgauss+2);
294  fdisplay += "+"; fdisplay += fname;
295  }
296 
297  nbgauss++;
298  }
299 
300  // perform the final fit and display the result
301  TF1 *f; if ( ( f = (TF1 *)gROOT->GetListOfFunctions()->FindObject("ResultFit") ) ) { delete f; }
302 
303  ffit.Remove(0,1);
304  printf("%s \n",ffit.Data());
305  f = new TF1("ResultFit",ffit.Data(),xlow,xhigh);
306 
307  // init parameters and limits
308  for ( i = 0; i < nbgauss; i++ ) {
309  if (fType == kGauss) {f->SetParameter(3*i,par[3*i]); f->SetParameter(3*i+1,par[3*i+1]); f->SetParameter(3*i+2,par[3*i+2]);}
310  if (fType == kSkewed) {f->SetParameter(6*i,par[6*i]); f->SetParameter(6*i+1,par[6*i+1]); f->SetParameter(6*i+2,par[6*i+2]); f->SetParameter(6*i+3,par[6*i+3]); f->SetParameter(6*i+4,par[6*i+4]); f->FixParameter(6*i+5,par[6*i+5]);}
311  // futur developments in case we would like to add limits
312  // f->SetParLimits(3*i,);
313  // f->SetParLimits(3*i+1,);
314  // f->SetParLimits(3*i+2,0.5*sigma,1.5*sigma);
315  //f->ReleaseParameter(3*i);f->ReleaseParameter(3*i+1);f->ReleaseParameter(3*i+2);
316  }
317  lochist->Fit(f,"VNR");
318 
319  Stat_t intensity, intensity_err;
320  printf("\n");
321  printf("******************* DOFIT1 RESULTS ******************* \n");
322  printf(" Chi2 %.2f / %d = %.2f \n",f->GetChisquare(),f->GetNDF(),f->GetChisquare()/f->GetNDF());
323 
324 // printf(" Background %f %f \n",par[0],par[1]);
325 
326  for ( i = 0; i < nbgauss; i++ ) {
327 
328  intensity = f->GetParameter(2+3*i)*f->GetParameter(3*i)*TMath::Sqrt(2*TMath::Pi());
329  intensity_err = intensity * (f->GetParError(1+3*i)/f->GetParameter(1+3*i) + f->GetParError(2+3*i)/f->GetParameter(2+3*i));
330 
331  printf(" Peak %d : Position %.2f +- %.3f, width %.3f +- %.3f, Height %.1f +- %.1f, \t Intensity %.1f +- %.1f\n",
332  i+1,f->GetParameter(1+3*i),f->GetParError(1+3*i),2*f->GetParameter(2+3*i),2*f->GetParError(2+3*i),
333  f->GetParameter(3*i),f->GetParError(3*i),intensity,intensity_err);
334 
335  sprintf(fname,"peak%d",i);
336  TF1 *fpeak;
337  if ( ( fpeak = (TF1 *)gROOT->GetListOfFunctions()->FindObject(fname) ) ) { delete fpeak; }
338 
339  if (fType == kGauss) {
340  fpeak = new TF1(fname,"gaus",f->GetParameter(1+3*i)-10,f->GetParameter(1+3*i)+10);
341  fpeak->SetLineStyle(3); fpeak->SetLineColor(16);
342 
343  fpeak->SetParameters(f->GetParameter(3*i),f->GetParameter(1+3*i),f->GetParameter(2+3*i));
344  fpeak->Draw("same");
345  }
346  if (fType == kSkewed) {
347  fpeak = new TF1(fname,SkewedGaussian,f->GetParameter(1+6*i)-10,f->GetParameter(1+6*i)+10,6);
348  fpeak->SetLineStyle(3); fpeak->SetLineColor(16);
349 
350  fpeak->SetParameters(f->GetParameter(6*i),f->GetParameter(1+6*i),f->GetParameter(2+6*i),f->GetParameter(3+6*i),f->GetParameter(4+6*i),f->GetParameter(5+6*i));
351  fpeak->Draw("same");
352  }
353  }
354  printf("****************************************************** \n");
355 
356  // to display the final result
357  par[0] = fbg->GetParameter(0);
358  par[1] = fbg->GetParameter(1); f->GetParameters(&par[2]);
359 
360  if ( ( f = (TF1 *)gROOT->GetListOfFunctions()->FindObject("DisplayFit") ) ) { delete f; }
361 
362  f = new TF1("DisplayFit",fdisplay.Data(),xlow,xhigh); f->SetParameters(par);
363  f->SetLineColor(6); f->SetLineWidth(3);
364 
365  delete lochist; // no longer useful
366 
367  f->Draw("same"); TVirtualPad::Pad()->Update();
368 }
369 
371  fType = type;
372 }
373 
374 
375 
376 
377 
void SetFunctionType(const FunctionType type)
Definition: PeakFitter.cpp:370
printf("******************************************************************** \n")
ClassImp(PeakFitter)
TGTextButton * fTextButtonDoFit
Definition: PeakFitter.h:201
void DoFit1(Float_t sigma=1.0)
Function to fit gaussians or skewed gaussian.
Definition: PeakFitter.cpp:206
PeakFitter is a tool class.
Definition: PeakFitter.h:179
TGTextButton * fTextButtonClearMarkers
Definition: PeakFitter.h:203
Double_t SkewedGaussian(Double_t *x, Double_t *par)
Definition: PeakFitter.cpp:64
void SetMode(Bool_t mode=true)
TGMainFrame * fMainFrame
Definition: PeakFitter.h:197
static ClickCollector * TheCollector()
TGTextButton * fTextButtonClearLastMarker
Definition: PeakFitter.h:202
TGTextButton * fTextButtonCollectOn
Definition: PeakFitter.h:199
ADF::LogMessage & endl(ADF::LogMessage &log)
header file for the calibration facility
TGTextButton * fTextButtonCollectOff
Definition: PeakFitter.h:200
TGGroupFrame * fGroupFrame1
Definition: PeakFitter.h:198
TGComboBox * fComboBoxFunctionType
Definition: PeakFitter.h:204
FunctionType fType
Definition: PeakFitter.h:206
void ClearLastMarker()
Definition: PeakFitter.cpp:189
virtual ~PeakFitter()
Definition: PeakFitter.cpp:144