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 11/2003 <mailto:markus@ifae.es>
|
---|
19 | !
|
---|
20 | ! Copyright: MAGIC Software Development, 2000-2002
|
---|
21 | !
|
---|
22 | !
|
---|
23 | \* ======================================================================== */
|
---|
24 |
|
---|
25 | //////////////////////////////////////////////////////////////////////////////
|
---|
26 | //
|
---|
27 | // MHGausEvent
|
---|
28 | //
|
---|
29 | // A base class for all kind of event which follow a Gaussian distribution
|
---|
30 | // with time, i.e. observables containing white noise.
|
---|
31 | //
|
---|
32 | // The class provides the basic tools for fitting,
|
---|
33 | // spectrum analysis, etc.
|
---|
34 | //
|
---|
35 | //////////////////////////////////////////////////////////////////////////////
|
---|
36 | #include "MHGausEvent.h"
|
---|
37 |
|
---|
38 | #include <TH1.h>
|
---|
39 | #include <TF1.h>
|
---|
40 |
|
---|
41 | #include "MFFT.h"
|
---|
42 | #include "MArray.h"
|
---|
43 |
|
---|
44 | #include "MLog.h"
|
---|
45 | #include "MLogManip.h"
|
---|
46 |
|
---|
47 | ClassImp(MHGausEvent);
|
---|
48 |
|
---|
49 | using namespace std;
|
---|
50 |
|
---|
51 | // --------------------------------------------------------------------------
|
---|
52 | //
|
---|
53 | // Default Constructor.
|
---|
54 | //
|
---|
55 | MHGausEvent::MHGausEvent(const char *name, const char *title)
|
---|
56 | : fHGausHist(NULL), fHPowerProbability(NULL),
|
---|
57 | fFGausFit(NULL), fFExpFit(NULL),
|
---|
58 | fEvents(NULL), fPowerSpectrum(NULL)
|
---|
59 | {
|
---|
60 |
|
---|
61 | fName = name ? name : "MHGausEvent";
|
---|
62 | fTitle = title ? title : "Events which follow a Gaussian distribution";
|
---|
63 |
|
---|
64 | Clear();
|
---|
65 | }
|
---|
66 |
|
---|
67 |
|
---|
68 | MHGausEvent::~MHGausEvent()
|
---|
69 | {
|
---|
70 | Clear();
|
---|
71 |
|
---|
72 | if (fHGausHist)
|
---|
73 | delete fHGausHist;
|
---|
74 | }
|
---|
75 |
|
---|
76 |
|
---|
77 |
|
---|
78 | void MHGausEvent::Clear(Option_t *o)
|
---|
79 | {
|
---|
80 |
|
---|
81 | fGausHistBins = 50;
|
---|
82 | fGausHistAxisFirst = 0.;
|
---|
83 | fGausHistAxisLast = 100.;
|
---|
84 |
|
---|
85 | fPowerProbabilityBins = 30;
|
---|
86 |
|
---|
87 | fProbLimit = 0.01;
|
---|
88 | fGausFitOK = kFALSE;
|
---|
89 | fExpFitOK = kFALSE;
|
---|
90 | fOscillating = kFALSE;
|
---|
91 |
|
---|
92 | fMean = 0.;
|
---|
93 | fSigma = 0.;
|
---|
94 | fMeanErr = 0.;
|
---|
95 | fSigmaErr = 0.;
|
---|
96 |
|
---|
97 | fProb = 0.;
|
---|
98 |
|
---|
99 | if (fHPowerProbability)
|
---|
100 | delete fHPowerProbability;
|
---|
101 | if (fFGausFit)
|
---|
102 | delete fFGausFit;
|
---|
103 | if (fEvents)
|
---|
104 | delete fEvents;
|
---|
105 | if (fPowerSpectrum)
|
---|
106 | delete fPowerSpectrum;
|
---|
107 | }
|
---|
108 |
|
---|
109 |
|
---|
110 | void MHGausEvent::Reset()
|
---|
111 | {
|
---|
112 |
|
---|
113 | Clear();
|
---|
114 | fHGausHist->Reset();
|
---|
115 |
|
---|
116 | }
|
---|
117 |
|
---|
118 | const Double_t MHGausEvent::GetChiSquare() const
|
---|
119 | {
|
---|
120 | return ( fFGausFit ? fFGausFit->GetChisquare() : 0.);
|
---|
121 | }
|
---|
122 |
|
---|
123 | const Int_t MHGausEvent::GetNdf() const
|
---|
124 | {
|
---|
125 | return ( fFGausFit ? fFGausFit->GetNDF() : 0);
|
---|
126 | }
|
---|
127 |
|
---|
128 |
|
---|
129 | const Double_t MHGausEvent::GetExpChiSquare() const
|
---|
130 | {
|
---|
131 | return ( fFExpFit ? fFExpFit->GetChisquare() : 0.);
|
---|
132 | }
|
---|
133 |
|
---|
134 |
|
---|
135 | const Int_t MHGausEvent::GetExpNdf() const
|
---|
136 | {
|
---|
137 | return ( fFExpFit ? fFExpFit->GetNDF() : 0);
|
---|
138 | }
|
---|
139 |
|
---|
140 | const Double_t MHGausEvent::GetExpProb() const
|
---|
141 | {
|
---|
142 | return ( fFExpFit ? fFExpFit->GetProb() : 0.);
|
---|
143 | }
|
---|
144 |
|
---|
145 | const Double_t MHGausEvent::GetOffset() const
|
---|
146 | {
|
---|
147 | return ( fFExpFit ? fFExpFit->GetParameter(0) : 0.);
|
---|
148 | }
|
---|
149 |
|
---|
150 | const Double_t MHGausEvent::GetSlope() const
|
---|
151 | {
|
---|
152 | return ( fFExpFit ? fFExpFit->GetParameter(1) : 0.);
|
---|
153 | }
|
---|
154 |
|
---|
155 |
|
---|
156 |
|
---|
157 | Bool_t MHGausEvent::CheckOscillations()
|
---|
158 | {
|
---|
159 |
|
---|
160 | if (fFExpFit)
|
---|
161 | return IsOscillating();
|
---|
162 |
|
---|
163 | if (!fEvents)
|
---|
164 | return kFALSE;
|
---|
165 |
|
---|
166 | //
|
---|
167 | // The number of entries HAS to be a potence of 2,
|
---|
168 | // so we can only cut out from the last potence of 2 to the rest.
|
---|
169 | // Another possibility would be to fill everything with
|
---|
170 | // zeros, but that gives a low frequency peak, which we would
|
---|
171 | // have to cut out later again.
|
---|
172 | //
|
---|
173 | // So, we have to live with the possibility that at the end
|
---|
174 | // of the calibration run, something has happened without noticing
|
---|
175 | // it...
|
---|
176 | //
|
---|
177 |
|
---|
178 | // This cuts only the non-used zero's, but MFFT will later cut the rest
|
---|
179 | MArray::StripZeros(*fEvents);
|
---|
180 |
|
---|
181 | MFFT fourier;
|
---|
182 |
|
---|
183 | fPowerSpectrum = fourier.PowerSpectrumDensity(fEvents);
|
---|
184 | fHPowerProbability = ProjectArray(*fPowerSpectrum, fPowerProbabilityBins,
|
---|
185 | "PowerProbability",
|
---|
186 | "Probability of Power occurrance");
|
---|
187 | //
|
---|
188 | // First guesses for the fit (should be as close to reality as possible,
|
---|
189 | //
|
---|
190 | const Double_t xmax = fHPowerProbability->GetXaxis()->GetXmax();
|
---|
191 |
|
---|
192 | fFExpFit = new TF1("FExpFit","exp([0]-[1]*x)",0.,xmax);
|
---|
193 |
|
---|
194 | const Double_t slope_guess = (TMath::Log(fHPowerProbability->GetEntries())+1.)/xmax;
|
---|
195 | const Double_t offset_guess = slope_guess*xmax;
|
---|
196 |
|
---|
197 | fFExpFit->SetParameters(offset_guess, slope_guess);
|
---|
198 | fFExpFit->SetParNames("Offset","Slope");
|
---|
199 | fFExpFit->SetParLimits(0,offset_guess/2.,2.*offset_guess);
|
---|
200 | fFExpFit->SetParLimits(1,slope_guess/1.5,1.5*slope_guess);
|
---|
201 | fFExpFit->SetRange(0.,xmax);
|
---|
202 |
|
---|
203 | fHPowerProbability->Fit(fFExpFit,"RQL0");
|
---|
204 |
|
---|
205 | if (GetExpProb() < fProbLimit)
|
---|
206 | fExpFitOK = kFALSE;
|
---|
207 |
|
---|
208 | // For the moment, this is the only check, later we can add more...
|
---|
209 | fOscillating = fExpFitOK;
|
---|
210 |
|
---|
211 | return fOscillating;
|
---|
212 | }
|
---|
213 |
|
---|
214 |
|
---|
215 | Bool_t MHGausEvent::IsEmpty() const
|
---|
216 | {
|
---|
217 | return !(fHGausHist->GetEntries());
|
---|
218 | }
|
---|
219 |
|
---|
220 | Bool_t MHGausEvent::IsOscillating()
|
---|
221 | {
|
---|
222 |
|
---|
223 | if (fFExpFit)
|
---|
224 | return fOscillating;
|
---|
225 |
|
---|
226 | return CheckOscillations();
|
---|
227 |
|
---|
228 | }
|
---|
229 |
|
---|
230 |
|
---|
231 | Bool_t MHGausEvent::FitGaus(Option_t *option)
|
---|
232 | {
|
---|
233 |
|
---|
234 | if (IsGausFitOK())
|
---|
235 | return kTRUE;
|
---|
236 |
|
---|
237 | //
|
---|
238 | // First, cut the edges which contain only zeros and rebin
|
---|
239 | // to about 20 bins.
|
---|
240 | //
|
---|
241 | // (ATTENTION: The Chisquare method is more sensitive,
|
---|
242 | // the _less_ bins, you have!)
|
---|
243 | //
|
---|
244 | Int_t newbins = 20;
|
---|
245 | MH::CutEdges(fHGausHist,newbins);
|
---|
246 |
|
---|
247 | //
|
---|
248 | // Get the fitting ranges
|
---|
249 | //
|
---|
250 | Axis_t rmin = fHGausHist->GetXaxis()->GetFirst();
|
---|
251 | Axis_t rmax = fHGausHist->GetXaxis()->GetLast();
|
---|
252 |
|
---|
253 | //
|
---|
254 | // First guesses for the fit (should be as close to reality as possible,
|
---|
255 | //
|
---|
256 | const Stat_t entries = fHGausHist->Integral("width");
|
---|
257 | const Double_t mu_guess = fHGausHist->GetBinCenter(fHGausHist->GetMaximumBin());
|
---|
258 | const Double_t sigma_guess = (rmax-rmin)/2.;
|
---|
259 | const Double_t area_guess = entries/TMath::Sqrt(TMath::TwoPi())/sigma_guess;
|
---|
260 |
|
---|
261 | fFGausFit = new TF1("GausFit","gaus",rmin,rmax);
|
---|
262 |
|
---|
263 | if (!fFGausFit)
|
---|
264 | {
|
---|
265 | *fLog << warn << dbginf << "WARNING: Could not create fit function for Gauss fit" << endl;
|
---|
266 | return kFALSE;
|
---|
267 | }
|
---|
268 |
|
---|
269 | fFGausFit->SetParameters(area_guess,mu_guess,sigma_guess);
|
---|
270 | fFGausFit->SetParNames("Area","#mu","#sigma");
|
---|
271 | fFGausFit->SetParLimits(0,0.,entries);
|
---|
272 | fFGausFit->SetParLimits(1,rmin,rmax);
|
---|
273 | fFGausFit->SetParLimits(2,0.,rmax-rmin);
|
---|
274 | fFGausFit->SetRange(rmin,rmax);
|
---|
275 |
|
---|
276 | fHGausHist->Fit(fFGausFit,option);
|
---|
277 |
|
---|
278 | fMean = fFGausFit->GetParameter(1);
|
---|
279 | fSigma = fFGausFit->GetParameter(2);
|
---|
280 | fMeanErr = fFGausFit->GetParError(1);
|
---|
281 | fSigmaErr = fFGausFit->GetParError(2);
|
---|
282 |
|
---|
283 | fProb = fFGausFit->GetProb();
|
---|
284 | //
|
---|
285 | // The fit result is accepted under condition:
|
---|
286 | // 1) The results are not nan's
|
---|
287 | // 2) The NDF is not smaller than fNDFLimit (5)
|
---|
288 | // 3) The Probability is greater than fProbLimit (default 0.001 == 99.9%)
|
---|
289 | //
|
---|
290 | if ( TMath::IsNaN(fMean)
|
---|
291 | || TMath::IsNaN(fMeanErr)
|
---|
292 | || TMath::IsNaN(fProb)
|
---|
293 | || TMath::IsNaN(fSigma)
|
---|
294 | || TMath::IsNaN(fSigmaErr) )
|
---|
295 | {
|
---|
296 | fGausFitOK = kFALSE;
|
---|
297 | return kFALSE;
|
---|
298 | }
|
---|
299 |
|
---|
300 | fGausFitOK = kTRUE;
|
---|
301 | return kTRUE;
|
---|
302 | }
|
---|
303 |
|
---|
304 | void MHGausEvent::Print(const Option_t *o) const
|
---|
305 | {
|
---|
306 |
|
---|
307 | *fLog << all << endl;
|
---|
308 | *fLog << all << "Results of the Gauss Fit: " << endl;
|
---|
309 | *fLog << all << "Mean: " << GetMean() << endl;
|
---|
310 | *fLog << all << "Sigma: " << GetSigma() << endl;
|
---|
311 | *fLog << all << "Chisquare: " << GetChiSquare() << endl;
|
---|
312 | *fLog << all << "DoF: " << GetNdf() << endl;
|
---|
313 | *fLog << all << "Probability: " << GetProb() << endl;
|
---|
314 | *fLog << all << endl;
|
---|
315 |
|
---|
316 | }
|
---|
317 |
|
---|