source: trunk/MagicSoft/Mars/mhflux/MHEffectiveOnTime.cc@ 7128

Last change on this file since 7128 was 7115, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 30.9 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): Thomas Bretz, 8/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19! Author(s): Wolfgang Wittek, 1/2002 <mailto:wittek@mppmu.mpg.de>
20!
21! Copyright: MAGIC Software Development, 2000-2004
22!
23!
24\* ======================================================================== */
25
26//////////////////////////////////////////////////////////////////////////////
27//
28// MHEffectiveOnTime
29//
30// Filling this you will get the effective on-time versus theta and
31// observation time.
32//
33// From this histogram the effective on-time is determined by a fit.
34// The result of the fit (see Fit()) and the fit-parameters (like chi^2)
35// are stored in corresponding histograms
36//
37// To determin the efective on time a poisson fit is done. For more details
38// please have a look into the source code of FitH() it should be simple
39// to understand. In this function a Delta-T distribution is fitted, while
40// Delta-T is the time between two consecutive events.
41//
42// The fit is done for projections of a 2D histogram in Theta and Delta T.
43// So you get the effective on time versus theta.
44//
45// To get the effective on-time versus time a histogram is filled with
46// the Delta-T distribution of a number of events set by SetNumEvents().
47// The default is 12000 (roughly 1min at 200Hz)
48//
49// For each "time-bin" the histogram is fitted and the resulting effective
50// on-time is stored in the fHTimeEffOn histogram. Each entry in this
51// histogram is the effective observation time between the upper and
52// lower edges of the bins.
53//
54// In addition the calculated effective on time is stored in a
55// "MEffectiveOnTime [MParameterDerr]" and the corresponding time-stamp
56// (the upper edge of the bin) "MTimeEffectiveOnTime [MTime]"
57//
58// The class takes two binnings from the Parameter list; if these binnings
59// are not available the defaultbinning is used:
60// MBinning("BinningDeltaT"); // Units of seconds
61// MBinning("BinningTheta"); // Units of degrees
62//
63//
64// Usage:
65// ------
66// MFillH fill("MHEffectiveOnTime", "MTime");
67// tlist.AddToList(&fill);
68//
69//
70// Input Container:
71// MPointingPos
72//
73// Output Container:
74// MEffectiveOnTime [MParameterDerr]
75// MTimeEffectiveOnTime [MTime]
76//
77//
78// ==========================================================================
79// Dear Colleagues,
80//
81// for the case that we are taking calibration events interleaved with
82// cosmics events the calculation of the effective observation time has to
83// be modified. I have summarized the proposed procedures in the note at the
84// end of this message. The formulas have been checked by a simulation.
85//
86// Comments are welcome.
87//
88// Regards, Wolfgang
89// --------------------------------------------------------------------------
90// Wolfgang Wittek
91// 2 Dec. 2004
92//
93// Calculation of the effective observation time when cosmics and calibration
94// events are taken simultaneously.
95// --------------------------------
96//
97// I. Introduction
98// ---------------
99// It is planned to take light calibration events (at a certain fixed frequency
100// lambda_calib) interlaced with cosmics events. The advantages of this
101// procedure are :
102//
103// - the pedestals, which would be determined from the cosmics, could be
104// used for both the calibration and the cosmics events
105//
106// - because calibration and cosmics events are taken quasi simultaneously,
107// rapid variations (in the order of a few minutes) of base lines and of the
108// photon/ADC conversion factors could be recognized and taken into account
109//
110// The effective observation time T_eff is defined as that time range, within
111// which the recorded number of events N_cosmics would be obtained under ideal
112// conditions (only cosmics, no dead time, no calibration events, ...).
113//
114// In the absence of calibration events the effective observation time can
115// be determined from the distribution of time differences 'dt' between
116// successive cosmics events (see first figure in the attached ps file).
117// The exponential slope 'lambda' of this distribution is the ideal cosmics
118// event rate. If 'N_cosmics' is the total number of recorded cosmics events,
119// T_eff is obtained by
120//
121// T_eff = N_cosmics / lambda
122//
123// In the case of a finite dead time 'dead', the distribution (for dt > dead) is
124// still exponential with the same slope 'lambda'. 'lambda' should be determined
125// in a region of 'dt' which is not affected by the dead time, i.e. at not too
126// low 'dt'.
127//
128//
129//
130// II. Problems in the presence of calibration events
131// --------------------------------------------------
132// If calibration events are taken interlaced with cosmics, and if the dead time
133// is negligible, the distribution of time differences 'dt' between cosmics can
134// be used for calculating the effective observation time, as if the calibration
135// events were not present.
136//
137// In the case of a non-negligible dead time 'dead', however, the distribution of
138// time differences between cosmics is distorted, because a cosmics event may be
139// lost due to the dead time after a calibration event. Even if the time
140// intervals are ignored which contain a calibration event,
141//
142//
143// ---|---------o--------|---------> t
144//
145// cosmics calib cosmics
146//
147// <----------------> <==== time interval to be ignored
148//
149//
150// the distribution of 'dt' is still distorted, because there would be no
151// 'dt' with dt > tau_calib = 1/lambda_calib. The distribution would also be
152// distorted in the region dt < tau_calib, due to calibration events occuring
153// shortly after cosmics events. As a result, the slope of the distribution of
154// 'dt' would not reflect the ideal cosmics event rate (see second figure; the
155// values assumed in the simulation are lambda = 200 Hz, lambda_calib = 50
156// Hz, dead = 0.001 sec, total time = 500 sec, number of generated cosmics
157// events = 100 000).
158//
159//
160// Note also that some calibration events will not be recorded due to the dead
161// time after a cosmics event.
162//
163//
164// III. Proposed procedures
165// ------------------------
166//
167// A) The ideal event rate 'lambda' may be calculated from the distribution of
168// the time difference 'dt_first' between a calibration event and the first
169// recorded cosmics event after the calibration event. In the region
170//
171// dead < dt_first < tau_calib
172//
173// the probability distribution of dt_first is given by
174//
175// p(dt_first) = c * exp(-lambda*dt_first)
176//
177// where c is a normalization constant. 'lambda' can be obtained by a simple
178// exponential fit to the experimental distribution of dt_first (see third
179// figure). The fit range should start well above the average value of the dead
180// time 'dead'.
181//
182//
183// B) One may consider those time intervals between recorded cosmics events, which
184// are completely contained in the region
185//
186// t_calib < t < t_calib + tau_calib
187//
188// where t_calib is the time of a recorded calibration event.
189//
190//
191// <--------------- tau_calib ----------->
192//
193//
194// 0 1 2 3 4 5 6 7 8 9 10
195// --|-o---|-|---|--|-|----|--|---|---|-|----o-|---|-|---------> t
196// ^ ^
197// | |
198// t_calib t_calib + tau_calib
199//
200//
201// In this example, of the time intervals 0 to 10 only the intervals 1 to 9
202// should be retained and plotted. The distribution of the length 'dt' of these
203// intervals in the region
204//
205// dead < dt < tau_calib
206//
207// is given by
208//
209// p(dt) = c * (tau_calib-dt-dead) * exp(-lambda*dt)
210//
211// A fit of this expression to the experimental distribution of 'dt' yields
212// 'lambda' (see fourth figure). For 'dead' an average value of the dead time
213// should be chosen, and the fit range should end well before dt = tau_calib-dead.
214//
215//
216// Method A has the advantage that the p(dt_first) does not depend on 'dead'.
217// 'dead' has to be considered when defining the fit range, both in method A and
218// in method B. In method B the event statistics is larger leading to a smaller
219// fitted error of 'lambda' than method A (see the figures).
220//
221//
222// The effective observation time is again obtained by
223//
224// T_eff = N_cosmics / lambda
225//
226// where N_cosmics is the total number of recorded cosmics events. Note that
227// N_cosmics is equal to
228//
229// N_cosmics = N_tot - N_calib
230//
231// where N_tot is the total number of recorded events (including the calibration
232// events) and N_calib is the number of recorded calibration events.
233//
234// Note that if time intervals are discarded for the determination of lambda,
235// the corresponding cosmics events need not and should not be discarded.
236//
237//
238// IV. Procedure if the calibration events are taken in bunches
239// ------------------------------------------------------------
240// In November 2004 the rate of calibration events is not constant. The events
241// are taken in 200 Hz bunches every second, such that the rate is 200 Hz for
242// 0.25 sec, followed by a gap of 0.75 sec. Then follows the next 200 Hz bunch.
243//
244// In this case it is proposed to consider for the calculation of 'lambda' only
245// the cosmics events within the gaps of 0.75 sec. For these cosmics events one
246// of the methods described in III. can be applied.
247//
248//
249// V. Alternative pocedure
250// -----------------------
251// The effective observation time can also be determined from the total
252// observation time and the total dead time. The latter is written out by the DAQ.
253// In this case it has to be made sure that the dead time is available in Mars
254// when the effective observation time is calculated.
255//
256//////////////////////////////////////////////////////////////////////////////
257#include "MHEffectiveOnTime.h"
258
259#include <TF1.h>
260#include <TMinuit.h>
261#include <TRandom.h>
262
263#include <TLatex.h>
264#include <TGaxis.h>
265#include <TCanvas.h>
266#include <TPaveStats.h>
267
268#include "MTime.h"
269#include "MParameters.h"
270#include "MPointingPos.h"
271
272#include "MBinning.h"
273#include "MParList.h"
274
275#include "MLog.h"
276#include "MLogManip.h"
277
278ClassImp(MHEffectiveOnTime);
279
280using namespace std;
281
282// --------------------------------------------------------------------------
283//
284// Default Constructor. It initializes all histograms.
285//
286MHEffectiveOnTime::MHEffectiveOnTime(const char *name, const char *title)
287 : fPointPos(0), fTime(0), fParam(0), fIsFinalized(kFALSE),
288 fNumEvents(200*60)/*, fNameProjDeltaT(Form("DeltaT_%p", this)),
289 fNameProjTheta(Form("Theta_%p", this))*/
290{
291 //
292 // set the name and title of this object
293 //
294 fName = name ? name : "MHEffectiveOnTime";
295 fTitle = title ? title : "Histogram to determin effective On-Time vs Time and Zenith Angle";
296
297 // Main histogram
298 fH2DeltaT.SetName("DeltaT");
299 fH2DeltaT.SetXTitle("\\Delta t [s]");
300 fH2DeltaT.SetYTitle("\\Theta [\\circ]");
301 fH2DeltaT.SetZTitle("Count");
302 fH2DeltaT.UseCurrentStyle();
303 fH2DeltaT.SetDirectory(NULL);
304
305 // Main histogram
306 fH1DeltaT.SetName("DeltaT");
307 fH1DeltaT.SetXTitle("\\Delta t [s]");
308 fH1DeltaT.SetYTitle("Counts");
309 fH1DeltaT.UseCurrentStyle();
310 fH1DeltaT.SetDirectory(NULL);
311
312 // effective on time versus theta
313 fHThetaEffOn.SetName("EffOnTheta");
314 fHThetaEffOn.SetTitle("Effective On Time T_{eff}");
315 fHThetaEffOn.SetXTitle("\\Theta [\\circ]");
316 fHThetaEffOn.SetYTitle("T_{eff} [s]");
317 fHThetaEffOn.UseCurrentStyle();
318 fHThetaEffOn.SetDirectory(NULL);
319 fHThetaEffOn.GetYaxis()->SetTitleOffset(1.2);
320 fHThetaEffOn.GetYaxis()->SetTitleColor(kBlue);
321 fHThetaEffOn.SetLineColor(kBlue);
322 //fHEffOn.Sumw2();
323
324 // effective on time versus time
325 fHTimeEffOn.SetName("EffOnTime");
326 fHTimeEffOn.SetTitle("Effective On Time T_{eff}");
327 fHTimeEffOn.SetXTitle("Time");
328 fHTimeEffOn.SetYTitle("T_{eff} [s]");
329 fHTimeEffOn.UseCurrentStyle();
330 fHTimeEffOn.SetDirectory(NULL);
331 fHTimeEffOn.GetYaxis()->SetTitleOffset(1.2);
332 fHTimeEffOn.GetXaxis()->SetLabelSize(0.033);
333 fHTimeEffOn.GetXaxis()->SetTimeFormat("%H:%M:%S %F1995-01-01 00:00:00 GMT");
334 fHTimeEffOn.GetXaxis()->SetTimeDisplay(1);
335 fHTimeEffOn.GetYaxis()->SetTitleColor(kBlue);
336 fHTimeEffOn.SetLineColor(kBlue);
337
338 // chi2 probability
339 fHThetaProb.SetName("ProbTheta");
340 fHThetaProb.SetTitle("\\chi^{2} Probability of Fit");
341 fHThetaProb.SetXTitle("\\Theta [\\circ]");
342 fHThetaProb.SetYTitle("p [%]");
343 fHThetaProb.UseCurrentStyle();
344 fHThetaProb.SetDirectory(NULL);
345 fHThetaProb.GetYaxis()->SetTitleOffset(1.2);
346 fHThetaProb.SetMaximum(101);
347 fHThetaProb.GetYaxis()->SetTitleColor(kBlue);
348 fHThetaProb.SetLineColor(kBlue);
349
350 // chi2 probability
351 fHTimeProb.SetName("ProbTime");
352 fHTimeProb.SetTitle("\\chi^{2} Probability of Fit");
353 fHTimeProb.SetXTitle("Time");
354 fHTimeProb.SetYTitle("p [%]");
355 fHTimeProb.UseCurrentStyle();
356 fHTimeProb.SetDirectory(NULL);
357 fHTimeProb.GetYaxis()->SetTitleOffset(1.2);
358 fHTimeProb.GetXaxis()->SetLabelSize(0.033);
359 fHTimeProb.GetXaxis()->SetTimeFormat("%H:%M:%S %F1995-01-01 00:00:00 GMT");
360 fHTimeProb.GetXaxis()->SetTimeDisplay(1);
361 fHTimeProb.SetMaximum(101);
362 fHTimeProb.GetYaxis()->SetTitleColor(kBlue);
363 fHTimeProb.SetLineColor(kBlue);
364
365 // lambda versus theta
366 fHThetaLambda.SetName("LambdaTheta");
367 fHThetaLambda.SetTitle("Slope (Rate) vs Theta");
368 fHThetaLambda.SetXTitle("\\Theta [\\circ]");
369 fHThetaLambda.SetYTitle("\\lambda [s^{-1}]");
370 fHThetaLambda.UseCurrentStyle();
371 fHThetaLambda.SetDirectory(NULL);
372 fHThetaLambda.SetLineColor(kGreen);
373
374 // lambda versus time
375 fHTimeLambda.SetName("LambdaTime");
376 fHTimeLambda.SetTitle("Slope (Rate) vs Time");
377 fHTimeLambda.SetXTitle("\\Time [\\circ]");
378 fHTimeLambda.SetYTitle("\\lambda [s^{-1}]");
379 fHTimeLambda.UseCurrentStyle();
380 fHTimeLambda.SetDirectory(NULL);
381 fHTimeLambda.GetYaxis()->SetTitleOffset(1.2);
382 fHTimeLambda.GetXaxis()->SetLabelSize(0.033);
383 fHTimeLambda.GetXaxis()->SetTimeFormat("%H:%M:%S %F1995-01-01 00:00:00 GMT");
384 fHTimeLambda.GetXaxis()->SetTimeDisplay(1);
385 fHTimeLambda.SetLineColor(kGreen);
386
387 // NDoF versus theta
388 fHThetaNDF.SetName("NDofTheta");
389 fHThetaNDF.SetTitle("Number of Degrees of freedom vs Theta");
390 fHThetaNDF.SetXTitle("\\Theta [\\circ]");
391 fHThetaNDF.SetYTitle("NDoF [#]");
392 fHThetaNDF.UseCurrentStyle();
393 fHThetaNDF.SetDirectory(NULL);
394 fHThetaNDF.SetLineColor(kGreen);
395
396 // NDoF versus time
397 /*
398 fHTimeNDF.SetName("NDofTime");
399 fHTimeNDF.SetTitle("Number of Degrees of freedom vs Time");
400 fHTimeNDF.SetXTitle("Time");
401 fHTimeNDF.SetYTitle("NDoF [#]");
402 fHTimeNDF.UseCurrentStyle();
403 fHTimeNDF.SetDirectory(NULL);
404 fHTimeNDF.GetYaxis()->SetTitleOffset(1.2);
405 fHTimeNDF.GetXaxis()->SetLabelSize(0.033);
406 fHTimeNDF.GetXaxis()->SetTimeFormat("%H:%M:%S %F1995-01-01 00:00:00 GMT");
407 fHTimeNDF.GetXaxis()->SetTimeDisplay(1);
408 fHTimeNDF.SetLineColor(kBlue);
409 */
410 // setup binning
411 MBinning btheta("BinningTheta");
412 btheta.SetEdgesCos(100, 0, 60);
413
414 MBinning btime("BinningDeltaT");
415 btime.SetEdges(50, 0, 0.1);
416
417 MH::SetBinning(&fH2DeltaT, &btime, &btheta);
418
419 btime.Apply(fH1DeltaT);
420
421 btheta.Apply(fHThetaEffOn);
422 btheta.Apply(fHThetaLambda);
423 btheta.Apply(fHThetaNDF);
424 btheta.Apply(fHThetaProb);
425 //btheta.Apply(fHChi2);
426}
427
428// --------------------------------------------------------------------------
429//
430// Set the binnings and prepare the filling of the histogram
431//
432Bool_t MHEffectiveOnTime::SetupFill(const MParList *plist)
433{
434 fPointPos = (MPointingPos*)plist->FindObject("MPointingPos");
435 if (!fPointPos)
436 {
437 *fLog << err << dbginf << "MPointingPos not found... aborting." << endl;
438 return kFALSE;
439 }
440
441 // FIXME: Remove const-qualifier from base-class!
442 fTime = (MTime*)const_cast<MParList*>(plist)->FindCreateObj("MTime", "MTimeEffectiveOnTime");
443 if (!fTime)
444 return kFALSE;
445 fParam = (MParameterDerr*)const_cast<MParList*>(plist)->FindCreateObj("MParameterDerr", "MEffectiveOnTime");
446 if (!fParam)
447 return kFALSE;
448
449 const MBinning* binsdtime = (MBinning*)plist->FindObject("BinningDeltaT");
450 const MBinning* binstheta = (MBinning*)plist->FindObject("BinningTheta");
451 if (binsdtime)
452 binsdtime->Apply(fH1DeltaT);
453 if (binstheta)
454 {
455 binstheta->Apply(fHThetaEffOn);
456 binstheta->Apply(fHThetaLambda);
457 binstheta->Apply(fHThetaNDF);
458 binstheta->Apply(fHThetaProb);
459 //binstheta->Apply(fHChi2);
460 }
461 if (binstheta && binsdtime)
462 SetBinning(&fH2DeltaT, binsdtime, binstheta);
463
464 return kTRUE;
465}
466
467// --------------------------------------------------------------------------
468//
469// Fit a single Delta-T distribution. See source code for more details
470//
471Bool_t MHEffectiveOnTime::FitH(TH1D *h, Double_t *res, Bool_t paint) const
472{
473 const Double_t Nm = h->Integral();
474
475 // FIXME: Do fit only if contents of bin has changed
476 if (Nm<=0)
477 return kFALSE;
478
479 // determine range (yq[0], yq[1]) of time differences
480 // where fit should be performed;
481 // require a fraction >=xq[0] of all entries to lie below yq[0]
482 // and a fraction <=xq[1] of all entries to lie below yq[1];
483 // within the range (yq[0], yq[1]) there must be no empty bin;
484 // choose pedestrian approach as long as GetQuantiles is not available
485 Double_t xq[2] = { 0.6, 0.99 };
486 Double_t yq[2];
487 h->GetQuantiles(2, yq, xq);
488
489 // Nmdel = Nm * binwidth, with Nm = number of observed events
490 const Double_t Nmdel = h->Integral("width");
491
492 //
493 // Setup Poisson function for the fit:
494 // lambda [Hz], N0 = ideal no of evts, del = bin width of dt
495 //
496 // parameter 0 = lambda
497 // parameter 1 = N0*del
498 //
499 TF1 func("Poisson", " [1]*[2] * [0] * exp(-[0] *x)");
500 //func.SetParNames("lambda", "N0", "del");
501
502 func.SetParameter(0, 200); // Hz
503 func.SetParameter(1, Nm);
504 func.FixParameter(2, Nmdel/Nm);
505
506 // options : N do not store the function, do not draw
507 // I use integral of function in bin rather than value at bin center
508 // R use the range specified in the function range
509 // Q quiet mode
510 h->Fit(&func, "NIQE", "", yq[0], yq[1]);
511
512 const Double_t chi2 = func.GetChisquare();
513 const Int_t NDF = func.GetNDF();
514
515 // was fit successful ?
516 const Bool_t ok = NDF>0 && chi2<3*NDF;
517
518 if (paint)
519 {
520 func.SetLineWidth(2);
521 func.SetLineColor(ok ? kGreen : kRed);
522 func.Paint("same");
523 }
524
525 const Double_t lambda = func.GetParameter(0);
526 //const Double_t N0 = func.GetParameter(1);
527 const Double_t prob = func.GetProb();
528
529 /*
530 *fLog << all << "Nm/lambda=" << Nm/lambda << " chi2/NDF=";
531 *fLog << (NDF ? chi2/NDF : 0.0) << " lambda=";
532 *fLog << lambda << " N0=" << N0 << endl;
533 */
534
535 Double_t emat[2][2];
536 gMinuit->mnemat((Double_t*)emat, 2);
537
538 const Double_t dldl = emat[0][0];
539 //const Double_t dN0dN0 = emat[1][1];
540
541 const Double_t teff = Nm/lambda;
542 const Double_t dteff = teff * TMath::Sqrt(dldl/(lambda*lambda) + 1.0/Nm);
543 const Double_t dl = TMath::Sqrt(dldl);
544
545 //const Double_t kappa = Nm/N0;
546 //const Double_t Rdead = 1.0 - kappa;
547 //const Double_t dRdead = kappa * TMath::Sqrt(dN0dN0/(N0*N0) + 1.0/Nm);
548
549 // the effective on time is Nm/lambda
550 res[0] = teff;
551 res[1] = dteff;
552
553 // plot chi2-probability of fit
554 res[2] = prob*100;
555
556 // lambda of fit
557 res[3] = lambda;
558 res[4] = dl;
559
560 // NDoF of fit
561 res[5] = NDF;
562
563 // Chi2
564 res[6] = chi2;
565
566 // Rdead (from fit) is the fraction from real time lost by the dead time
567 //fHRdead.SetBinContent(i, Rdead);
568 //fHRdead.SetBinError (i,dRdead);
569
570 return ok;
571}
572
573// --------------------------------------------------------------------------
574//
575// Fit a all bins of the distribution in theta. Store the result in the
576// Theta-Histograms
577//
578void MHEffectiveOnTime::FitThetaBins()
579{
580 fHThetaEffOn.Reset();
581 fHThetaProb.Reset();
582 fHThetaLambda.Reset();
583 fHThetaNDF.Reset();
584
585 const TString name = Form("CalcTheta%d", (UInt_t)gRandom->Uniform(999999999));
586
587 // nbins = number of Theta bins
588 const Int_t nbins = fH2DeltaT.GetNbinsY();
589
590 TH1D *h=0;
591 for (int i=1; i<=nbins; i++)
592 {
593 // TH1D &h = *hist->ProjectionX("Calc-theta", i, i);
594 h = fH2DeltaT.ProjectionX(name, i, i, "E");
595
596 Double_t res[7];
597 if (!FitH(h, res))
598 continue;
599
600 // the effective on time is Nm/lambda
601 fHThetaEffOn.SetBinContent(i, res[0]);
602 fHThetaEffOn.SetBinError (i, res[1]);
603
604 // plot chi2-probability of fit
605 fHThetaProb.SetBinContent(i, res[2]);
606
607 // plot chi2/NDF of fit
608 //fHChi2.SetBinContent(i, res[3]);
609
610 // lambda of fit
611 fHThetaLambda.SetBinContent(i, res[3]);
612 fHThetaLambda.SetBinError (i, res[4]);
613
614 // NDoF of fit
615 fHThetaNDF.SetBinContent(i, res[5]);
616
617 // Rdead (from fit) is the fraction from real time lost by the dead time
618 //fHRdead.SetBinContent(i, Rdead);
619 //fHRdead.SetBinError (i,dRdead);
620 }
621
622 // Histogram is reused via gROOT->FindObject()
623 // Need to be deleted only once
624 if (h)
625 delete h;
626}
627
628// --------------------------------------------------------------------------
629//
630// Fit the single-time-bin histogram. Store the result in the
631// Time-Histograms
632//
633void MHEffectiveOnTime::FitTimeBin()
634{
635 //
636 // Fit histogram
637 //
638 Double_t res[7];
639 if (!FitH(&fH1DeltaT, res))
640 return;
641
642 // Reset Histogram
643 fH1DeltaT.Reset();
644
645 //
646 // Prepare Histogram
647 //
648
649 // Get number of bins
650 const Int_t n = fHTimeEffOn.GetNbinsX();
651
652 // Enhance binning
653 MBinning bins;
654 bins.SetEdges(fHTimeEffOn, 'x');
655 bins.AddEdge(fLastTime.GetAxisTime());
656 bins.Apply(fHTimeEffOn);
657 bins.Apply(fHTimeProb);
658 bins.Apply(fHTimeLambda);
659 //bins.Apply(fHTimeNDF);
660
661 //
662 // Fill histogram
663 //
664 fHTimeEffOn.SetBinContent(n, res[0]);
665 fHTimeEffOn.SetBinError(n, res[1]);
666
667 fHTimeProb.SetBinContent(n, res[2]);
668
669 fHTimeLambda.SetBinContent(n, res[3]);
670 fHTimeLambda.SetBinError(n, res[4]);
671
672 //fHTimeNDF.SetBinContent(n, res[5]);
673
674 //
675 // Now prepare output
676 //
677 fParam->SetVal(res[0], res[1]);
678 fParam->SetReadyToSave();
679
680 *fTime = fLastTime;
681
682 // Include the current event
683 fTime->Plus1ns();
684
685 *fLog << fLastTime << ": Val=" << res[0] << " Err=" << res[1] << endl;
686}
687
688// --------------------------------------------------------------------------
689//
690// Fill the histogram
691//
692Bool_t MHEffectiveOnTime::Fill(const MParContainer *par, const Stat_t w)
693{
694 const MTime *time = dynamic_cast<const MTime*>(par);
695 if (!time)
696 {
697 *fLog << err << "ERROR - MHEffectiveOnTime::Fill without argument or container doesn't inherit from MTime... abort." << endl;
698 return kFALSE;
699 }
700
701 //
702 // If this is the first call we have to initialize the time-histogram
703 //
704 if (fLastTime==MTime())
705 {
706 MBinning bins;
707 bins.SetEdges(1, time->GetAxisTime()-fNumEvents/200, time->GetAxisTime());
708 bins.Apply(fHTimeEffOn);
709 bins.Apply(fHTimeProb);
710 bins.Apply(fHTimeLambda);
711 //bins.Apply(fHTimeNDF);
712
713 fParam->SetVal(0, 0);
714 fParam->SetReadyToSave();
715
716 *fTime = *time;
717
718 // Make this 1ns before the first event!
719 fTime->Minus1ns();
720 }
721
722 //
723 // Fill time difference into the histograms
724 //
725 const Double_t dt = *time-fLastTime;
726 fLastTime = *time;
727
728 fH2DeltaT.Fill(dt, fPointPos->GetZd(), w);
729 fH1DeltaT.Fill(dt, w);
730
731 //
732 // If we reached the event number limit for the time-bins fit the
733 // histogram - if it fails try again when 1.6% more events available
734 //
735 const Int_t n = (Int_t)fH1DeltaT.GetEntries();
736 if (n>=fNumEvents && n%(fNumEvents/60)==0)
737 FitTimeBin();
738
739 return kTRUE;
740}
741
742// --------------------------------------------------------------------------
743//
744// Fit the theta projections of the 2D histogram and the 1D Delta-T
745// distribution
746//
747Bool_t MHEffectiveOnTime::Finalize()
748{
749 FitThetaBins();
750 FitTimeBin();
751
752 fIsFinalized = kTRUE;
753
754 return kTRUE;
755}
756
757// --------------------------------------------------------------------------
758//
759// Paint the integral and the error on top of the histogram
760//
761void MHEffectiveOnTime::PaintText(Double_t val, Double_t error) const
762{
763 TLatex text(0.45, 0.94, Form("T_{eff} = %.1fs \\pm %.1fs", val, error));
764 text.SetBit(TLatex::kTextNDC);
765 text.SetTextSize(0.04);
766 text.Paint();
767}
768
769void MHEffectiveOnTime::PaintText(Double_t *res) const
770{
771 TLatex text(0.27, 0.94, Form("T_{eff}=%.1fs\\pm%.1fs \\lambda=%.1f\\pm%.1fHz p=%.1f%% \\chi^{2}/%d=%.1f",
772 res[0], res[1], res[3], res[4], res[2], (int)res[5], res[6]/res[5]));
773 text.SetBit(TLatex::kTextNDC);
774 text.SetTextSize(0.04);
775 text.Paint();
776}
777
778void MHEffectiveOnTime::PaintProb(TH1 &h) const
779{
780 Double_t sum = 0;
781 Int_t n = 0;
782 for (int i=0; i<h.GetNbinsX(); i++)
783 if (h.GetBinContent(i+1)>0)
784 {
785 sum += h.GetBinContent(i+1);
786 n++;
787 }
788
789 if (n==0)
790 return;
791
792 TLatex text(0.47, 0.94, Form("\\bar{p} = %.1f%%", sum/n));
793 text.SetBit(TLatex::kTextNDC);
794 text.SetTextSize(0.04);
795 text.Paint();
796}
797
798void MHEffectiveOnTime::UpdateRightAxis(TH1 &h)
799{
800 const Double_t max = h.GetMaximum()*1.1;
801 if (max==0)
802 return;
803
804 h.SetNormFactor(h.Integral()*gPad->GetUymax()/max);
805
806 TGaxis *axis = (TGaxis*)gPad->FindObject("RightAxis");
807 if (!axis)
808 return;
809
810 axis->SetX1(gPad->GetUxmax());
811 axis->SetX2(gPad->GetUxmax());
812 axis->SetY1(gPad->GetUymin());
813 axis->SetY2(gPad->GetUymax());
814 axis->SetWmax(max);
815}
816
817// --------------------------------------------------------------------------
818//
819// Prepare painting the histograms
820//
821void MHEffectiveOnTime::Paint(Option_t *opt)
822{
823 TH1D *h=0;
824 TPaveStats *st=0;
825
826 TString o(opt);
827 if (o==(TString)"fit")
828 {
829 TVirtualPad *pad = gPad;
830
831 for (int x=0; x<2; x++)
832 for (int y=0; y<3; y++)
833 {
834 TVirtualPad *p=gPad->GetPad(x+1)->GetPad(y+1);
835 if (!(st = dynamic_cast<TPaveStats*>(p->GetPrimitive("stats"))))
836 continue;
837
838 if (st->GetOptStat()==11)
839 continue;
840
841 const Double_t y1 = st->GetY1NDC();
842 const Double_t y2 = st->GetY2NDC();
843 const Double_t x1 = st->GetX1NDC();
844 const Double_t x2 = st->GetX2NDC();
845
846 st->SetY1NDC((y2-y1)/3+y1);
847 st->SetX1NDC((x2-x1)/3+x1);
848 st->SetOptStat(11);
849 }
850
851 pad->GetPad(1)->cd(1);
852 if ((h = (TH1D*)gPad->FindObject("ProjDeltaT"/*fNameProjDeltaT*/)))
853 {
854 h = fH2DeltaT.ProjectionX("ProjDeltaT"/*fNameProjDeltaT*/, -1, 9999, "E");
855 if (h->GetEntries()>0)
856 gPad->SetLogy();
857 }
858
859 pad->GetPad(2)->cd(1);
860 if ((h = (TH1D*)gPad->FindObject("ProjTheta"/*fNameProjTheta*/)))
861 fH2DeltaT.ProjectionY("ProjTheta"/*fNameProjTheta*/, -1, 9999, "E");
862
863 if (!fIsFinalized)
864 FitThetaBins();
865 return;
866 }
867 if (o==(TString)"paint")
868 {
869 if ((h = (TH1D*)gPad->FindObject("ProjDeltaT"/*fNameProjDeltaT*/)))
870 {
871 Double_t res[7];
872 FitH(h, res, kTRUE);
873 PaintText(res);
874 }
875 return;
876 }
877
878 if (o==(TString)"timendf")
879 {
880 // UpdateRightAxis(fHTimeNDF);
881 // FIXME: first bin?
882 PaintProb(fHTimeProb);
883 }
884
885 if (o==(TString)"thetandf")
886 {
887 UpdateRightAxis(fHThetaNDF);
888 // FIXME: first bin?
889 PaintProb(fHThetaProb);
890 }
891
892 h=0;
893 if (o==(TString)"theta")
894 {
895 h = &fHThetaEffOn;
896 UpdateRightAxis(fHThetaLambda);
897 }
898 if (o==(TString)"time")
899 {
900 h = &fHTimeEffOn;
901 UpdateRightAxis(fHTimeLambda);
902 }
903
904 if (!h)
905 return;
906
907 Double_t error = 0;
908 for (int i=0; i<h->GetXaxis()->GetNbins(); i++)
909 error += h->GetBinError(i);
910
911 PaintText(h->Integral(), error);
912}
913
914void MHEffectiveOnTime::DrawRightAxis(const char *title)
915{
916 TGaxis *axis = new TGaxis(gPad->GetUxmax(), gPad->GetUymin(),
917 gPad->GetUxmax(), gPad->GetUymax(),
918 0, 1, 510, "+L");
919 axis->SetName("RightAxis");
920 axis->SetTitle(title);
921 axis->SetTitleOffset(0.9);
922 axis->SetTextColor(kGreen);
923 axis->CenterTitle();
924 axis->SetBit(kCanDelete);
925 axis->Draw();
926}
927
928// --------------------------------------------------------------------------
929//
930// Draw the histogram
931//
932void MHEffectiveOnTime::Draw(Option_t *opt)
933{
934 TVirtualPad *pad = gPad ? gPad : MakeDefCanvas(this);
935 pad->SetBorderMode(0);
936
937 AppendPad("fit");
938
939 pad->Divide(2, 1, 1e-10, 1e-10);
940
941 TH1 *h;
942
943 pad->cd(1);
944 gPad->SetBorderMode(0);
945 gPad->Divide(1, 3, 1e-10, 1e-10);
946 pad->GetPad(1)->cd(1);
947 gPad->SetBorderMode(0);
948 h = fH2DeltaT.ProjectionX("ProjDeltaT"/*fNameProjDeltaT*/, -1, 9999, "E");
949 h->SetTitle("Distribution of \\Delta t [s]");
950 h->SetXTitle("\\Delta t [s]");
951 h->SetYTitle("Counts");
952 h->SetDirectory(NULL);
953 h->SetMarkerStyle(kFullDotMedium);
954 h->SetBit(kCanDelete);
955 h->Draw();
956 AppendPad("paint");
957
958 pad->GetPad(1)->cd(2);
959 gPad->SetBorderMode(0);
960 fHTimeProb.Draw();
961 AppendPad("timendf");
962 //fHTimeNDF.Draw("same");
963 //DrawRightAxis("NDF");
964
965 pad->GetPad(1)->cd(3);
966 gPad->SetBorderMode(0);
967 fHTimeEffOn.Draw();
968 AppendPad("time");
969 fHTimeLambda.Draw("same");
970 DrawRightAxis("\\lambda [s^{-1}]");
971
972 pad->cd(2);
973 gPad->SetBorderMode(0);
974 gPad->Divide(1, 3, 1e-10, 1e-10);
975
976 pad->GetPad(2)->cd(1);
977 gPad->SetBorderMode(0);
978 h = fH2DeltaT.ProjectionY("ProjTheta"/*fNameProjTheta*/, -1, 9999, "E");
979 h->SetTitle("Distribution of \\Theta [\\circ]");
980 h->SetXTitle("\\Theta [\\circ]");
981 h->SetYTitle("Counts");
982 h->SetDirectory(NULL);
983 h->SetMarkerStyle(kFullDotMedium);
984 h->SetBit(kCanDelete);
985 h->GetYaxis()->SetTitleOffset(1.1);
986 h->Draw();
987
988 pad->GetPad(2)->cd(2);
989 gPad->SetBorderMode(0);
990 fHThetaProb.Draw();
991 AppendPad("thetandf");
992 fHThetaNDF.Draw("same");
993 DrawRightAxis("NDF");
994
995 pad->GetPad(2)->cd(3);
996 gPad->SetBorderMode(0);
997 fHThetaEffOn.Draw();
998 AppendPad("theta");
999 fHThetaLambda.Draw("same");
1000 DrawRightAxis("\\lambda [s^{-1}]");
1001}
Note: See TracBrowser for help on using the repository browser.