source: trunk/MagicSoft/Mars/mcalib/MHGausEvents.cc@ 3620

Last change on this file since 3620 was 3617, checked in by gaug, 22 years ago
*** empty log message ***
File size: 20.0 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Markus Gaug 02/2004 <mailto:markus@ifae.es>
19!
20! Copyright: MAGIC Software Development, 2000-2004
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MHGausEvents
28//
29// A base class for events which are believed to follow a Gaussian distribution
30// with time, e.g. calibration events, observables containing white noise, ...
31//
32// MHGausEvents derives from MH, thus all features of MH can be used by a class
33// deriving from MHGausEvents, especially the filling functions.
34//
35// The central objects are:
36//
37// 1) The TH1F fHGausHist:
38// ====================
39//
40// It is created with a default name and title and resides in directory NULL.
41// - Any class deriving from MHGausEvents needs to apply a binning to fHGausHist
42// (e.g. with the function TH1F::SetBins(..) )
43// - The histogram is filled with the functions FillHist() or FillHistAndArray().
44// - The histogram can be fitted with the function FitGaus(). This involves stripping
45// of all zeros at the lower and upper end of the histogram and re-binning to
46// a new number of bins, specified in the variable fBinsAfterStripping.
47// - The fit result's probability is compared to a reference probability fProbLimit
48// The NDF is compared to fNDFLimit and a check is made whether results are NaNs.
49// Accordingly, a flag IsGausFitOK() is set.
50//
51// 2) The TArrayF fEvents:
52// ==========================
53//
54// It is created with 0 entries and not expanded unless FillArray() or FillHistAndArray()
55// are called.
56// - A first call to FillArray() or FillHistAndArray() initializes fEvents by default
57// to 512 entries.
58// - Any later call to FillArray() or FillHistAndArray() fills up the array.
59// Reaching the limit, the array is expanded by a factor 2.
60// - The array can be fourier-transformed into the array fPowerSpectrum.
61// Note that any FFT accepts only number of events which are a power of 2.
62// Thus, fEvents is cut to the next power of 2 smaller than its actual number of entries.
63// Be aware that you might lose information at the end of your analysis.
64// - Calling the function CreateFourierSpectrum() creates the array fPowerSpectrum
65// and its projection fHPowerProbability which in turn is fit to an exponential.
66// - The fit result's probability is compared to a referenc probability fProbLimit
67// and accordingly the flag IsExpFitOK() is set.
68// - The flag IsFourierSpectrumOK() is set accordingly to IsExpFitOK().
69// Later, a closer check will be installed.
70// - You can display all arrays by calls to: CreateGraphEvents() and
71// CreateGraphPowerSpectrum() and successive calls to the corresponding Getters.
72//
73//////////////////////////////////////////////////////////////////////////////
74#include "MHGausEvents.h"
75
76#include <TH1.h>
77#include <TF1.h>
78#include <TGraph.h>
79#include <TPad.h>
80#include <TVirtualPad.h>
81#include <TCanvas.h>
82#include <TStyle.h>
83
84#include "MFFT.h"
85#include "MArray.h"
86
87#include "MH.h"
88
89#include "MLog.h"
90#include "MLogManip.h"
91
92ClassImp(MHGausEvents);
93
94using namespace std;
95
96const Float_t MHGausEvents::fgProbLimit = 0.001;
97const Int_t MHGausEvents::fgNDFLimit = 2;
98const Int_t MHGausEvents::fgPowerProbabilityBins = 20;
99const Int_t MHGausEvents::fgBinsAfterStripping = 40;
100// --------------------------------------------------------------------------
101//
102// Default Constructor.
103// Sets:
104// - the default Probability Bins for fPowerProbabilityBins (fgPowerProbabilityBins)
105// - the default Probability Limit for fProbLimit (fgProbLimit)
106// - the default NDF Limit for fNDFLimit (fgNDFLimit)
107// - the default number of bins after stripping for fBinsAfterStipping (fgBinsAfterStipping)
108// - the default name of the fHGausHist ("HGausHist")
109// - the default title of the fHGausHist ("Histogram of Events with Gaussian Distribution")
110// - the default directory of the fHGausHist (NULL)
111//
112// Initializes:
113// - fEvents to 0 entries
114// - fHGausHist()
115// - all other pointers to NULL
116// - all variables to 0.
117// - all flags to kFALSE
118//
119MHGausEvents::MHGausEvents(const char *name, const char *title)
120 : fEventFrequency(0), fHPowerProbability(NULL),
121 fPowerSpectrum(NULL),
122 fGraphEvents(NULL), fGraphPowerSpectrum(NULL),
123 fHGausHist(), fEvents(0),
124 fFGausFit(NULL), fFExpFit(NULL)
125{
126
127 fName = name ? name : "MHGausEvents";
128 fTitle = title ? title : "Events with expected Gaussian distributions";
129
130 Clear();
131
132 SetPowerProbabilityBins();
133 SetProbLimit();
134 SetNDFLimit();
135 SetBinsAfterStripping();
136
137 fHGausHist.SetName("HGausHist");
138 fHGausHist.SetTitle("Histogram of Events with Gaussian Distribution");
139 // important, other ROOT will not draw the axes:
140 fHGausHist.UseCurrentStyle();
141 fHGausHist.SetDirectory(NULL);
142}
143
144
145
146// --------------------------------------------------------------------------
147//
148// Default Destructor.
149//
150// Deletes (if Pointer is not NULL):
151//
152// - fHPowerProbability
153// - fFGausFit
154// - fFExpFit
155// - fPowerSpectrum
156// - fGraphEvents
157// - fGraphPowerSpectrum
158//
159MHGausEvents::~MHGausEvents()
160{
161
162 // delete histograms
163 if (fHPowerProbability)
164 delete fHPowerProbability;
165
166 // delete fits
167 if (fFGausFit)
168 delete fFGausFit;
169 if (fFExpFit)
170 delete fFExpFit;
171
172 // delete arrays
173 if (fPowerSpectrum)
174 delete fPowerSpectrum;
175
176 // delete graphs
177 if (fGraphEvents)
178 delete fGraphEvents;
179 if (fGraphPowerSpectrum)
180 delete fGraphPowerSpectrum;
181}
182
183// --------------------------------------------------------------------------
184//
185// Sets:
186// - all other pointers to NULL
187// - all variables to 0., except fEventFrequency
188// - all flags to kFALSE
189//
190// Deletes (if not NULL):
191// - all pointers
192//
193void MHGausEvents::Clear(Option_t *o)
194{
195
196 SetGausFitOK ( kFALSE );
197 SetExpFitOK ( kFALSE );
198 SetFourierSpectrumOK( kFALSE );
199
200 fMean = 0.;
201 fSigma = 0.;
202 fMeanErr = 0.;
203 fSigmaErr = 0.;
204 fProb = 0.;
205
206 fCurrentSize = 0;
207
208 if (fHPowerProbability)
209 {
210 delete fHPowerProbability;
211 fHPowerProbability = NULL;
212 }
213
214 // delete fits
215 if (fFGausFit)
216 {
217 delete fFGausFit;
218 fFGausFit = NULL;
219 }
220
221 if (fFExpFit)
222 {
223 delete fFExpFit;
224 fFExpFit = NULL;
225 }
226
227 // delete arrays
228 if (fPowerSpectrum)
229 {
230 delete fPowerSpectrum;
231 fPowerSpectrum = NULL;
232 }
233
234 // delete graphs
235 if (fGraphEvents)
236 {
237 delete fGraphEvents;
238 fGraphEvents = NULL;
239 }
240
241 if (fGraphPowerSpectrum)
242 {
243 delete fGraphPowerSpectrum;
244 fGraphPowerSpectrum = NULL;
245 }
246}
247
248// --------------------------------------------------------------------------
249//
250// Executes:
251// - Clear()
252// - fHGausHist.Reset()
253// - fEvents.Set(0)
254//
255void MHGausEvents::Reset()
256{
257
258 Clear();
259 fHGausHist.Reset();
260 fEvents.Set(0);
261
262}
263
264// --------------------------------------------------------------------------
265//
266// Executes:
267// - FillArray()
268// - FillHist()
269//
270Bool_t MHGausEvents::FillHistAndArray(const Float_t f)
271{
272
273 FillArray(f);
274 return FillHist(f);
275}
276
277// --------------------------------------------------------------------------
278//
279// Fills fHGausHist with f
280// Returns kFALSE, if overflow or underflow occurred, else kTRUE
281//
282Bool_t MHGausEvents::FillHist(const Float_t f)
283{
284 return fHGausHist.Fill(f) > -1;
285}
286
287// --------------------------------------------------------------------------
288//
289// Fill fEvents with f
290// If size of fEvents is 0, initializes it to 512
291// If size of fEvents is smaller than fCurrentSize, double the size
292// Increase fCurrentSize by 1
293//
294void MHGausEvents::FillArray(const Float_t f)
295{
296 if (fEvents.GetSize() == 0)
297 fEvents.Set(512);
298
299 if (fCurrentSize >= fEvents.GetSize())
300 fEvents.Set(fEvents.GetSize()*2);
301
302 fEvents.AddAt(f,fCurrentSize++);
303}
304
305
306const Double_t MHGausEvents::GetChiSquare() const
307{
308 return ( fFGausFit ? fFGausFit->GetChisquare() : 0.);
309}
310
311const Int_t MHGausEvents::GetNdf() const
312{
313 return ( fFGausFit ? fFGausFit->GetNDF() : 0);
314}
315
316
317const Double_t MHGausEvents::GetExpChiSquare() const
318{
319 return ( fFExpFit ? fFExpFit->GetChisquare() : 0.);
320}
321
322
323const Int_t MHGausEvents::GetExpNdf() const
324{
325 return ( fFExpFit ? fFExpFit->GetNDF() : 0);
326}
327
328
329const Double_t MHGausEvents::GetExpProb() const
330{
331 return ( fFExpFit ? fFExpFit->GetProb() : 0.);
332}
333
334
335const Double_t MHGausEvents::GetOffset() const
336{
337 return ( fFExpFit ? fFExpFit->GetParameter(0) : 0.);
338}
339
340
341const Double_t MHGausEvents::GetSlope() const
342{
343 return ( fFExpFit ? fFExpFit->GetParameter(1) : 0.);
344}
345
346
347const Bool_t MHGausEvents::IsEmpty() const
348{
349 return !(fHGausHist.GetEntries());
350}
351
352
353const Bool_t MHGausEvents::IsFourierSpectrumOK() const
354{
355 return TESTBIT(fFlags,kFourierSpectrumOK);
356}
357
358
359const Bool_t MHGausEvents::IsGausFitOK() const
360{
361 return TESTBIT(fFlags,kGausFitOK);
362}
363
364
365const Bool_t MHGausEvents::IsExpFitOK() const
366{
367 return TESTBIT(fFlags,kExpFitOK);
368}
369
370
371// -------------------------------------------------------------------
372//
373// The flag setters are to be used ONLY for Monte-Carlo!!
374//
375void MHGausEvents::SetGausFitOK(const Bool_t b)
376{
377 b ? SETBIT(fFlags,kGausFitOK) : CLRBIT(fFlags,kGausFitOK);
378
379}
380// -------------------------------------------------------------------
381//
382// The flag setters are to be used ONLY for Monte-Carlo!!
383//
384void MHGausEvents::SetExpFitOK(const Bool_t b)
385{
386
387 b ? SETBIT(fFlags,kExpFitOK) : CLRBIT(fFlags,kExpFitOK);
388}
389
390// -------------------------------------------------------------------
391//
392// The flag setters are to be used ONLY for Monte-Carlo!!
393//
394void MHGausEvents::SetFourierSpectrumOK(const Bool_t b)
395{
396
397 b ? SETBIT(fFlags,kFourierSpectrumOK) : CLRBIT(fFlags,kFourierSpectrumOK);
398}
399
400
401// -------------------------------------------------------------------
402//
403// Create the fourier spectrum using the class MFFT.
404// The result is projected into a histogram and fitted by an exponential
405//
406void MHGausEvents::CreateFourierSpectrum()
407{
408
409 if (fFExpFit)
410 return;
411
412 //
413 // The number of entries HAS to be a potence of 2,
414 // so we can only cut out from the last potence of 2 to the rest.
415 // Another possibility would be to fill everything with
416 // zeros, but that gives a low frequency peak, which we would
417 // have to cut out later again.
418 //
419 // So, we have to live with the possibility that at the end
420 // of the calibration run, something has happened without noticing
421 // it...
422 //
423
424 // This cuts only the non-used zero's, but MFFT will later cut the rest
425 MArray::StripZeros(fEvents);
426
427 MFFT fourier;
428
429 fPowerSpectrum = fourier.PowerSpectrumDensity(&fEvents);
430 fHPowerProbability = ProjectArray(*fPowerSpectrum, fPowerProbabilityBins,
431 "PowerProbability",
432 "Probability of Power occurrance");
433 fHPowerProbability->SetXTitle("P(f)");
434 fHPowerProbability->SetDirectory(NULL);
435 //
436 // First guesses for the fit (should be as close to reality as possible,
437 //
438 const Double_t xmax = fHPowerProbability->GetXaxis()->GetXmax();
439
440 fFExpFit = new TF1("FExpFit","exp([0]-[1]*x)",0.,xmax);
441
442 const Double_t slope_guess = (TMath::Log(fHPowerProbability->GetEntries())+1.)/xmax;
443 const Double_t offset_guess = slope_guess*xmax;
444
445 fFExpFit->SetParameters(offset_guess, slope_guess);
446 fFExpFit->SetParNames("Offset","Slope");
447 fFExpFit->SetParLimits(0,offset_guess/2.,2.*offset_guess);
448 fFExpFit->SetParLimits(1,slope_guess/1.5,1.5*slope_guess);
449 fFExpFit->SetRange(0.,xmax);
450
451 fHPowerProbability->Fit(fFExpFit,"RQL0");
452
453 if (GetExpProb() > fProbLimit)
454 SetExpFitOK(kTRUE);
455
456 //
457 // For the moment, this is the only check, later we can add more...
458 //
459 SetFourierSpectrumOK(IsExpFitOK());
460
461 return;
462}
463
464// -------------------------------------------------------------------
465//
466// Fit fGausHist with a Gaussian after stripping zeros from both ends
467// and rebinned to the number of bins specified in fBinsAfterStripping
468//
469// The fit results are retrieved and stored in class-own variables.
470//
471// A flag IsGausFitOK() is set according to whether the fit probability
472// is smaller or bigger than fProbLimit, whether the NDF is bigger than
473// fNDFLimit and whether results are NaNs.
474//
475Bool_t MHGausEvents::FitGaus(Option_t *option, const Double_t xmin, const Double_t xmax)
476{
477
478 if (IsGausFitOK())
479 return kTRUE;
480
481 //
482 // First, strip the zeros from the edges which contain only zeros and rebin
483 // to about fBinsAfterStripping bins.
484 //
485 // (ATTENTION: The Chisquare method is more sensitive,
486 // the _less_ bins, you have!)
487 //
488 StripZeros(&fHGausHist,fBinsAfterStripping);
489
490 //
491 // Get the fitting ranges
492 //
493 Axis_t rmin = (xmin==0.) && (xmax==0.) ? fHGausHist.GetBinCenter(fHGausHist.GetXaxis()->GetFirst()) : xmin;
494 Axis_t rmax = (xmin==0.) && (xmax==0.) ? fHGausHist.GetBinCenter(fHGausHist.GetXaxis()->GetLast()) : xmax;
495
496 //
497 // First guesses for the fit (should be as close to reality as possible,
498 //
499 const Stat_t entries = fHGausHist.Integral("width");
500 const Double_t mu_guess = fHGausHist.GetBinCenter(fHGausHist.GetMaximumBin());
501 const Double_t sigma_guess = fHGausHist.GetRMS();
502 const Double_t area_guess = entries/TMath::Sqrt(TMath::TwoPi())/sigma_guess;
503
504 fFGausFit = new TF1("GausFit","gaus",rmin,rmax);
505
506 if (!fFGausFit)
507 {
508 *fLog << warn << dbginf << "WARNING: Could not create fit function for Gauss fit" << endl;
509 return kFALSE;
510 }
511
512 fFGausFit->SetParameters(area_guess,mu_guess,sigma_guess);
513 fFGausFit->SetParNames("Area","#mu","#sigma");
514 fFGausFit->SetParLimits(0,0.,area_guess*1.5);
515 fFGausFit->SetParLimits(1,rmin,rmax);
516 fFGausFit->SetParLimits(2,0.,rmax-rmin);
517 fFGausFit->SetRange(rmin,rmax);
518
519 fHGausHist.Fit(fFGausFit,option);
520
521
522 fMean = fFGausFit->GetParameter(1);
523 fSigma = fFGausFit->GetParameter(2);
524 fMeanErr = fFGausFit->GetParError(1);
525 fSigmaErr = fFGausFit->GetParError(2);
526 fProb = fFGausFit->GetProb();
527 //
528 // The fit result is accepted under condition:
529 // 1) The results are not nan's
530 // 2) The NDF is not smaller than fNDFLimit (5)
531 // 3) The Probability is greater than fProbLimit (default 0.001 == 99.9%)
532 //
533 if ( TMath::IsNaN(fMean)
534 || TMath::IsNaN(fMeanErr)
535 || TMath::IsNaN(fProb)
536 || TMath::IsNaN(fSigma)
537 || TMath::IsNaN(fSigmaErr)
538 || fFGausFit->GetNDF() < fNDFLimit
539 || fProb < fProbLimit )
540 return kFALSE;
541
542 SetGausFitOK(kTRUE);
543 return kTRUE;
544}
545
546// -----------------------------------------------------------------------------------
547//
548// A default print
549//
550void MHGausEvents::Print(const Option_t *o) const
551{
552
553 *fLog << all << endl;
554 *fLog << all << "Results of the Gauss Fit: " << endl;
555 *fLog << all << "Mean: " << GetMean() << endl;
556 *fLog << all << "Sigma: " << GetSigma() << endl;
557 *fLog << all << "Chisquare: " << GetChiSquare() << endl;
558 *fLog << all << "DoF: " << GetNdf() << endl;
559 *fLog << all << "Probability: " << GetProb() << endl;
560 *fLog << all << endl;
561
562}
563
564// ----------------------------------------------------------------------------------
565//
566// Create a graph to display the array fEvents
567// If the variable fEventFrequency is set, the x-axis is transformed into real time.
568//
569void MHGausEvents::CreateGraphEvents()
570{
571
572 MArray::StripZeros(fEvents);
573
574 const Int_t n = fEvents.GetSize();
575
576 fGraphEvents = new TGraph(n,CreateEventXaxis(n),fEvents.GetArray());
577 fGraphEvents->SetTitle("Evolution of Events with time");
578 fGraphEvents->GetXaxis()->SetTitle((fEventFrequency) ? "Time [s]" : "Event Nr.");
579}
580
581// ----------------------------------------------------------------------------------
582//
583// Create a graph to display the array fPowerSpectrum
584// If the variable fEventFrequency is set, the x-axis is transformed into real frequency.
585//
586void MHGausEvents::CreateGraphPowerSpectrum()
587{
588
589 MArray::StripZeros(*fPowerSpectrum);
590
591 const Int_t n = fPowerSpectrum->GetSize();
592
593 fGraphPowerSpectrum = new TGraph(n,CreatePSDXaxis(n),fPowerSpectrum->GetArray());
594 fGraphPowerSpectrum->SetTitle("Power Spectrum Density");
595 fGraphPowerSpectrum->GetXaxis()->SetTitle((fEventFrequency) ? "Frequency [Hz]" : "Frequency");
596 fGraphPowerSpectrum->GetYaxis()->SetTitle("P(f)");
597}
598
599// -----------------------------------------------------------------------------
600//
601// Create the x-axis for the event graph
602//
603Float_t *MHGausEvents::CreateEventXaxis(Int_t n)
604{
605
606 Float_t *xaxis = new Float_t[n];
607
608 if (fEventFrequency)
609 for (Int_t i=0;i<n;i++)
610 xaxis[i] = (Float_t)i/fEventFrequency;
611 else
612 for (Int_t i=0;i<n;i++)
613 xaxis[i] = (Float_t)i;
614
615 return xaxis;
616
617}
618
619// -----------------------------------------------------------------------------
620//
621// Create the x-axis for the event graph
622//
623Float_t *MHGausEvents::CreatePSDXaxis(Int_t n)
624{
625
626 Float_t *xaxis = new Float_t[n];
627
628 if (fEventFrequency)
629 for (Int_t i=0;i<n;i++)
630 xaxis[i] = 0.5*(Float_t)i*fEventFrequency/n;
631 else
632 for (Int_t i=0;i<n;i++)
633 xaxis[i] = 0.5*(Float_t)i/n;
634
635 return xaxis;
636
637}
638
639// -----------------------------------------------------------------------------
640//
641// Default draw:
642//
643// The following options can be chosen:
644//
645// "EVENTS": displays a TGraph of the array fEvents
646// "FOURIER": display a TGraph of the fourier transform of fEvents
647// displays the projection of the fourier transform with the fit
648//
649void MHGausEvents::Draw(const Option_t *opt)
650{
651
652 TVirtualPad *pad = gPad ? gPad : MH::MakeDefCanvas(this,600, 900);
653
654 TString option(opt);
655 option.ToLower();
656
657 Int_t win = 1;
658
659 if (option.Contains("events"))
660 {
661 option.ReplaceAll("events","");
662 win += 1;
663 }
664 if (option.Contains("fourier"))
665 {
666 option.ReplaceAll("fourier","");
667 win += 2;
668 }
669
670 pad->SetTicks();
671 pad->SetBorderMode(0);
672 pad->Divide(1,win);
673 pad->cd(1);
674
675 if (!IsEmpty())
676 gPad->SetLogy();
677
678 fHGausHist.Draw(opt);
679
680 if (fFGausFit)
681 {
682 fFGausFit->SetLineColor(IsGausFitOK() ? kGreen : kRed);
683 fFGausFit->Draw("same");
684 }
685 switch (win)
686 {
687 case 2:
688 pad->cd(2);
689 DrawEvents();
690 break;
691 case 3:
692 pad->cd(2);
693 DrawPowerSpectrum(*pad,3);
694 break;
695 case 4:
696 pad->cd(2);
697 DrawEvents();
698 pad->cd(3);
699 DrawPowerSpectrum(*pad,4);
700 break;
701 }
702}
703
704void MHGausEvents::DrawEvents()
705{
706
707 if (!fGraphEvents)
708 CreateGraphEvents();
709
710 fGraphEvents->SetBit(kCanDelete);
711 fGraphEvents->SetTitle("Events with time");
712 fGraphEvents->Draw("AL");
713
714}
715
716
717void MHGausEvents::DrawPowerSpectrum(TVirtualPad &pad, Int_t i)
718{
719
720 if (fPowerSpectrum)
721 {
722 if (!fGraphPowerSpectrum)
723 CreateGraphPowerSpectrum();
724
725 fGraphPowerSpectrum->Draw("AL");
726 fGraphPowerSpectrum->SetBit(kCanDelete);
727 }
728
729 pad.cd(i);
730
731 if (fHPowerProbability && fHPowerProbability->GetEntries() > 0)
732 {
733 gPad->SetLogy();
734 fHPowerProbability->Draw();
735 if (fFExpFit)
736 {
737 fFExpFit->SetLineColor(IsExpFitOK() ? kGreen : kRed);
738 fFExpFit->Draw("same");
739 }
740 }
741}
742
743
Note: See TracBrowser for help on using the repository browser.