source: trunk/MagicSoft/Mars/mhist/MHCamera.cc@ 3936

Last change on this file since 3936 was 3936, checked in by gaug, 20 years ago
*** empty log message ***
File size: 51.2 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, 05/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19! Author(s): Harald Kornmayer, 1/2001
20! Author(s): Markus Gaug, 03/2004 <mailto:markus@ifae.es>
21!
22! Copyright: MAGIC Software Development, 2000-2004
23!
24!
25\* ======================================================================== */
26
27/////////////////////////////////////////////////////////////////////////////
28//
29// MHCamera
30//
31// Camera Display, based on a TH1D. Pleas be carefull using the
32// underlaying TH1D.
33//
34// To change the scale to a logarithmic scale SetLogy() of the Pad.
35//
36// Be carefull: Entries in this context means Entries/bin or Events
37//
38// FIXME? Maybe MHCamera can take the fLog object from MGeomCam?
39//
40////////////////////////////////////////////////////////////////////////////
41#include "MHCamera.h"
42
43#include <fstream>
44#include <iostream>
45
46#include <TBox.h>
47#include <TArrow.h>
48#include <TLatex.h>
49#include <TStyle.h>
50#include <TCanvas.h>
51#include <TArrayF.h>
52#include <TRandom.h>
53#include <TPaveText.h>
54#include <TPaveStats.h>
55#include <TClonesArray.h>
56#include <THistPainter.h>
57#include <THLimitsFinder.h>
58#include <TProfile.h>
59#include <TH1.h>
60#include <TF1.h>
61
62#include "MLog.h"
63#include "MLogManip.h"
64
65#include "MH.h"
66#include "MHexagon.h"
67
68#include "MGeomPix.h"
69#include "MGeomCam.h"
70
71#include "MCamEvent.h"
72
73#define kItemsLegend 48 // see SetPalette(1,0)
74
75ClassImp(MHCamera);
76
77using namespace std;
78
79void MHCamera::Init()
80{
81 UseCurrentStyle();
82
83 SetDirectory(NULL);
84
85 SetLineColor(kGreen);
86 SetMarkerStyle(kFullDotMedium);
87 SetXTitle("Pixel Index");
88
89 fNotify = new TList;
90 fNotify->SetBit(kMustCleanup);
91 gROOT->GetListOfCleanups()->Add(fNotify);
92
93#if ROOT_VERSION_CODE < ROOT_VERSION(3,01,06)
94 SetPalette(1, 0);
95#else
96 SetInvDeepBlueSeaPalette();
97#endif
98}
99
100// ------------------------------------------------------------------------
101//
102// Default Constructor. To be used by the root system ONLY.
103//
104MHCamera::MHCamera() : TH1D(), fGeomCam(NULL), fColors(kItemsLegend)
105{
106 Init();
107}
108
109// ------------------------------------------------------------------------
110//
111// Constructor. Makes a clone of MGeomCam. Removed the TH1D from the
112// current directory. Calls Sumw2(). Set the histogram line color
113// (for error bars) to Green and the marker style to kFullDotMedium.
114//
115MHCamera::MHCamera(const MGeomCam &geom, const char *name, const char *title)
116: fGeomCam(NULL), fColors(kItemsLegend)
117{
118 //fGeomCam = (MGeomCam*)geom.Clone();
119 SetGeometry(geom, name, title);
120 Init();
121
122 //
123 // root 3.02
124 // * base/inc/TObject.h:
125 // register BIT(8) as kNoContextMenu. If an object has this bit set it will
126 // not get an automatic context menu when clicked with the right mouse button.
127}
128
129void MHCamera::SetGeometry(const MGeomCam &geom, const char *name, const char *title)
130{
131 SetNameTitle(name, title);
132
133 TAxis &x = *GetXaxis();
134
135 SetBins(geom.GetNumPixels(), 0, 1);
136 x.Set(geom.GetNumPixels(), -0.5, geom.GetNumPixels()-0.5);
137
138 //SetBins(geom.GetNumPixels(), -0.5, geom.GetNumPixels()-0.5);
139 //Rebuild();
140
141 Sumw2(); // necessary?
142
143 if (fGeomCam)
144 delete fGeomCam;
145 fGeomCam = (MGeomCam*)geom.Clone();
146
147 fUsed.Set(geom.GetNumPixels());
148 for (Int_t i=0; i<fNcells-2; i++)
149 ResetUsed(i);
150}
151
152// ------------------------------------------------------------------------
153//
154// Destructor. Deletes the cloned fGeomCam and the notification list.
155//
156MHCamera::~MHCamera()
157{
158 if (fGeomCam)
159 delete fGeomCam;
160 if (fNotify)
161 delete fNotify;
162}
163
164// ------------------------------------------------------------------------
165//
166// Return kTRUE for sector<0. Otherwise return kTRUE only if the specified
167// sector idx matches the sector of the pixel with index idx.
168//
169Bool_t MHCamera::MatchSector(Int_t idx, const TArrayI &sector, const TArrayI &aidx) const
170{
171 const MGeomPix &pix = (*fGeomCam)[idx];
172 return FindVal(sector, pix.GetSector()) && FindVal(aidx, pix.GetAidx());
173}
174
175// ------------------------------------------------------------------------
176//
177// Taken from TH1D::Fill(). Uses the argument directly as bin index.
178// Doesn't increment the number of entries.
179//
180// -*-*-*-*-*-*-*-*Increment bin with abscissa X by 1*-*-*-*-*-*-*-*-*-*-*
181// ==================================
182//
183// if x is less than the low-edge of the first bin, the Underflow bin is incremented
184// if x is greater than the upper edge of last bin, the Overflow bin is incremented
185//
186// If the storage of the sum of squares of weights has been triggered,
187// via the function Sumw2, then the sum of the squares of weights is incremented
188// by 1 in the bin corresponding to x.
189//
190// -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
191Int_t MHCamera::Fill(Axis_t x)
192{
193#if ROOT_VERSION_CODE > ROOT_VERSION(3,05,00)
194 if (fBuffer) return BufferFill(x,1);
195#endif
196 const Int_t bin = (Int_t)x+1;
197 AddBinContent(bin);
198 if (fSumw2.fN)
199 fSumw2.fArray[bin]++;
200
201 if (bin<=0 || bin>fNcells-2)
202 return -1;
203
204 fTsumw++;
205 fTsumw2++;
206 fTsumwx += x;
207 fTsumwx2 += x*x;
208 return bin;
209}
210
211// ------------------------------------------------------------------------
212//
213// Taken from TH1D::Fill(). Uses the argument directly as bin index.
214// Doesn't increment the number of entries.
215//
216// -*-*-*-*-*-*Increment bin with abscissa X with a weight w*-*-*-*-*-*-*-*
217// =============================================
218//
219// if x is less than the low-edge of the first bin, the Underflow bin is incremented
220// if x is greater than the upper edge of last bin, the Overflow bin is incremented
221//
222// If the storage of the sum of squares of weights has been triggered,
223// via the function Sumw2, then the sum of the squares of weights is incremented
224// by w^2 in the bin corresponding to x.
225//
226// -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
227Int_t MHCamera::Fill(Axis_t x, Stat_t w)
228{
229#if ROOT_VERSION_CODE > ROOT_VERSION(3,05,00)
230 if (fBuffer) return BufferFill(x,w);
231#endif
232 const Int_t bin = (Int_t)x+1;
233 AddBinContent(bin, w);
234 if (fSumw2.fN)
235 fSumw2.fArray[bin] += w*w;
236
237 if (bin<=0 || bin>fNcells-2)
238 return -1;
239
240 const Stat_t z = (w > 0 ? w : -w);
241 fTsumw += z;
242 fTsumw2 += z*z;
243 fTsumwx += z*x;
244 fTsumwx2 += z*x*x;
245 return bin;
246}
247
248// ------------------------------------------------------------------------
249//
250// Use x and y in millimeters
251//
252Int_t MHCamera::Fill(Axis_t x, Axis_t y, Stat_t w)
253{
254 if (fNcells<=1 || IsFreezed())
255 return -1;
256
257 for (Int_t idx=0; idx<fNcells-2; idx++)
258 {
259 MHexagon hex((*fGeomCam)[idx]);
260 if (hex.DistanceToPrimitive(x, y)>0)
261 continue;
262
263 SetUsed(idx);
264 return Fill(idx, w);
265 }
266 return -1;
267}
268
269// ------------------------------------------------------------------------
270//
271// Call this if you want to change the display status (displayed or not)
272// for all pixels. val==0 means that the pixel is not displayed.
273//
274void MHCamera::SetUsed(const TArrayC &arr)
275{
276 if (fNcells-2 != arr.GetSize())
277 {
278 gLog << warn << "WARNING - MHCamera::SetUsed: array size mismatch... ignored." << endl;
279 return;
280 }
281
282 for (Int_t idx=0; idx<fNcells-2; idx++)
283 arr[idx] ? SetUsed(idx) : ResetUsed(idx);
284}
285
286// ------------------------------------------------------------------------
287//
288// Return the mean value of all entries which are used if all=kFALSE and
289// of all entries if all=kTRUE if sector<0. If sector>=0 only
290// entries with match the given sector are taken into account.
291//
292Stat_t MHCamera::GetMeanSectors(const TArrayI &sector, const TArrayI &aidx, Bool_t all) const
293{
294 if (fNcells<=1)
295 return 0;
296
297 Int_t n=0;
298
299 Stat_t mean = 0;
300 for (int i=0; i<fNcells-2; i++)
301 {
302 if ((all || IsUsed(i)) && MatchSector(i, sector, aidx))
303 {
304 mean += fArray[i+1];
305 n++;
306 }
307 }
308
309 return n==0 ? 0 : Profile(mean/n);
310}
311
312// ------------------------------------------------------------------------
313//
314// Return the variance of all entries which are used if all=kFALSE and
315// of all entries if all=kTRUE if sector<0. If sector>=0 only
316// entries with match the given sector are taken into account.
317//
318Stat_t MHCamera::GetRmsSectors(const TArrayI &sector, const TArrayI &aidx, Bool_t all) const
319{
320 if (fNcells<=1)
321 return -1;
322
323 Int_t n=0;
324
325 Stat_t sum = 0;
326 Stat_t sq = 0;
327 for (int i=0; i<fNcells-2; i++)
328 {
329 if ((all || IsUsed(i)) && MatchSector(i, sector, aidx))
330 {
331 sum += fArray[i+1];
332 sq += fArray[i+1]*fArray[i+1];
333 n++;
334 }
335 }
336
337 if (n==0)
338 return 0;
339
340 sum /= n;
341 sq /= n;
342
343 return Profile(TMath::Sqrt(sq-sum*sum));
344}
345
346// ------------------------------------------------------------------------
347//
348// Return the minimum contents of all pixels (if all is set, otherwise
349// only of all 'used' pixels), fMinimum if fMinimum set. If sector>=0
350// only pixels with matching sector number are taken into account.
351//
352Double_t MHCamera::GetMinimumSectors(const TArrayI &sector, const TArrayI &aidx, Bool_t all) const
353{
354 if (fMinimum != -1111)
355 return fMinimum;
356
357 if (fNcells<=1)
358 return 0;
359
360 Double_t minimum=FLT_MAX;
361
362 for (Int_t idx=0; idx<fNcells-2; idx++)
363 if (MatchSector(idx, sector, aidx) && (all || IsUsed(idx)) && fArray[idx+1]<minimum)
364 minimum = fArray[idx+1];
365
366 return Profile(minimum);
367}
368
369// ------------------------------------------------------------------------
370//
371// Return the maximum contents of all pixels (if all is set, otherwise
372// only of all 'used' pixels), fMaximum if fMaximum set. If sector>=0
373// only pixels with matching sector number are taken into account.
374//
375Double_t MHCamera::GetMaximumSectors(const TArrayI &sector, const TArrayI &aidx, Bool_t all) const
376{
377 if (fMaximum!=-1111)
378 return fMaximum;
379
380 if (fNcells<=1)
381 return 1;
382
383 Double_t maximum=-FLT_MAX;
384 for (Int_t idx=0; idx<fNcells-2; idx++)
385 if (MatchSector(idx, sector, aidx) && (all || IsUsed(idx)) && fArray[idx+1]>maximum)
386 maximum = fArray[idx+1];
387
388 return Profile(maximum);
389}
390
391// ------------------------------------------------------------------------
392//
393// Call this function to draw the camera layout into your canvas.
394// Setup a drawing canvas. Add this object and all child objects
395// (hexagons, etc) to the current pad. If no pad exists a new one is
396// created. (To access the 'real' pad containing the camera you have
397// to do a cd(1) in the current layer.
398//
399// To draw a camera into its own pad do something like:
400//
401// MGeomCamMagic m;
402// MHCamera *d=new MHCamera(m);
403//
404// TCanvas *c = new TCanvas;
405// c->Divide(2,1);
406// c->cd(1);
407//
408// d->FillRandom();
409// d->Draw();
410// d->SetBit(kCanDelete);
411//
412// There are several drawing options:
413// 'hist' Draw as a standard TH1 histogram (value vs. pixel index)
414// 'box' Draw hexagons which size is in respect to its contents
415// 'nocol' Leave the 'boxed' hexagons empty
416// 'pixelindex' Display the pixel index in each pixel
417// 'sectorindex' Display the sector index in each pixel
418// 'content' Display the relative content aligned to GetMaximum() and
419// GeMinimum() ((val-min)/(max-min))
420// 'proj' Display the y-projection of the histogram
421// 'same' Draw trandparent pixels on top of an existing pad. This
422// makes it possible to draw the camera image on top of an
423// existing TH2, but also allows for distorted camera images
424//
425void MHCamera::Draw(Option_t *option)
426{
427 const Bool_t hassame = TString(option).Contains("same", TString::kIgnoreCase) && gPad;
428
429 // root 3.02:
430 // gPad->SetFixedAspectRatio()
431 const Color_t col = gPad ? gPad->GetFillColor() : 16;
432 TVirtualPad *pad = gPad ? gPad : MH::MakeDefCanvas("CamDisplay", "Mars Camera Display", 656, 600);
433
434 if (!hassame)
435 {
436 pad->SetBorderMode(0);
437 pad->SetFillColor(col);
438
439 //
440 // Create an own pad for the MHCamera-Object which can be
441 // resized in paint to keep the correct aspect ratio
442 //
443 pad->Divide(1, 1, 0, 0, col);
444 pad->cd(1);
445 gPad->SetBorderMode(0);
446 }
447
448 AppendPad(option);
449 //fGeomCam->AppendPad();
450
451 //
452 // Do not change gPad. The user should not see, that Draw
453 // changes gPad...
454 //
455 if (!hassame)
456 pad->cd();
457}
458
459// ------------------------------------------------------------------------
460//
461// This is TObject::DrawClone but completely ignores
462// gROOT->GetSelectedPad(). tbretz had trouble with this in the past.
463// If this makes trouble please write a bug report.
464//
465TObject *MHCamera::DrawClone(Option_t *option) const
466{
467 // Draw a clone of this object in the current pad
468
469 //TVirtualPad *pad = gROOT->GetSelectedPad();
470 TVirtualPad *padsav = gPad;
471 //if (pad) pad->cd();
472
473 TObject *newobj = Clone();
474
475 if (!newobj)
476 return 0;
477
478 /*
479 if (pad) {
480 if (strlen(option)) pad->GetListOfPrimitives()->Add(newobj,option);
481 else pad->GetListOfPrimitives()->Add(newobj,GetDrawOption());
482 pad->Modified(kTRUE);
483 pad->Update();
484 if (padsav) padsav->cd();
485 return newobj;
486 }
487 */
488
489 TString opt(option);
490 opt.ToLower();
491
492 newobj->Draw(opt.IsNull() ? GetDrawOption() : option);
493
494 if (padsav)
495 padsav->cd();
496
497 return newobj;
498}
499
500// ------------------------------------------------------------------------
501//
502// Creates a TH1D which contains the projection of the contents of the
503// MHCamera onto the y-axis. The maximum and minimum are calculated
504// such that a slighly wider range than (GetMinimum(), GetMaximum()) is
505// displayed using THLimitsFinder::OptimizeLimits.
506//
507// If no name is given the newly allocated histogram is removed from
508// the current directory calling SetDirectory(0) in any other case
509// the newly created histogram is removed from the current directory
510// and added to gROOT such the gROOT->FindObject can find the histogram.
511//
512// If the standard name "_py" is given "_py" is appended to the name
513// of the MHCamera and the corresponding histogram is searched using
514// gROOT->FindObject and updated with the present projection.
515//
516// It is the responsibility of the user to make sure, that the newly
517// created histogram is freed correctly.
518//
519// Currently the new histogram is restrictred to 50 bins.
520// Maybe a optimal number can be calulated from the number of
521// bins on the x-axis of the MHCamera?
522//
523// The code was taken mainly from TH2::ProjectX such the interface
524// is more or less the same than to TH2-projections.
525//
526// If sector>=0 only entries with matching sector index are taken
527// into account.
528//
529TH1D *MHCamera::ProjectionS(const TArrayI &sector, const TArrayI &aidx, const char *name) const
530{
531 Int_t nbins = 50;
532
533 // Create the projection histogram
534 TString pname(name);
535 if (name=="_py")
536 {
537 pname.Prepend(GetName());
538 if (sector.GetSize()>0)
539 {
540 pname += ";";
541 for (int i=0; i<sector.GetSize(); i++)
542 pname += sector[i];
543 }
544 if (aidx.GetSize()>0)
545 {
546 pname += ";";
547 for (int i=0; i<aidx.GetSize(); i++)
548 pname += aidx[i];
549 }
550 }
551
552 TH1D *h1=0;
553
554 //check if histogram with identical name exist
555 TObject *h1obj = gROOT->FindObject(pname);
556 if (h1obj && h1obj->InheritsFrom("TH1D")) {
557 h1 = (TH1D*)h1obj;
558 h1->Reset();
559 }
560
561 if (!h1)
562 {
563 Double_t min = GetMinimumSectors(sector, aidx);
564 Double_t max = GetMaximumSectors(sector, aidx);
565
566 Int_t newbins=0;
567
568 THLimitsFinder::OptimizeLimits(nbins, newbins, min, max, kFALSE);
569
570 h1 = new TH1D(pname, GetTitle(), nbins, min, max);
571 h1->SetDirectory(pname.IsNull() ? NULL : gROOT);
572 h1->SetXTitle(GetYaxis()->GetTitle());
573 h1->SetYTitle("Counts");
574 //h1->Sumw2();
575 }
576
577 // Fill the projected histogram
578 for (Int_t idx=0; idx<fNcells-2; idx++)
579 if (IsUsed(idx) && MatchSector(idx, sector, aidx))
580 h1->Fill(GetBinContent(idx+1));
581
582 return h1;
583}
584
585// ------------------------------------------------------------------------
586//
587// Creates a TH1D which contains the projection of the contents of the
588// MHCamera onto the radius from the camera center.
589// The maximum and minimum are calculated
590// such that a slighly wider range than (GetMinimum(), GetMaximum()) is
591// displayed using THLimitsFinder::OptimizeLimits.
592//
593// If no name is given the newly allocated histogram is removed from
594// the current directory calling SetDirectory(0) in any other case
595// the newly created histogram is removed from the current directory
596// and added to gROOT such the gROOT->FindObject can find the histogram.
597//
598// If the standard name "_rad" is given "_rad" is appended to the name
599// of the MHCamera and the corresponding histogram is searched using
600// gROOT->FindObject and updated with the present projection.
601//
602// It is the responsibility of the user to make sure, that the newly
603// created histogram is freed correctly.
604//
605// Currently the new histogram is restrictred to 50 bins.
606// Maybe a optimal number can be calulated from the number of
607// bins on the x-axis of the MHCamera?
608//
609// The code was taken mainly from TH2::ProjectX such the interface
610// is more or less the same than to TH2-projections.
611//
612// If sector>=0 only entries with matching sector index are taken
613// into account.
614//
615TProfile *MHCamera::RadialProfileS(const TArrayI &sector, const TArrayI &aidx, const char *name, const Int_t nbins) const
616{
617
618 // Create the projection histogram
619 TString pname(name);
620 if (name=="_rad")
621 {
622 pname.Prepend(GetName());
623 if (sector.GetSize()>0)
624 {
625 pname += ";";
626 for (int i=0; i<sector.GetSize(); i++)
627 pname += sector[i];
628 }
629 if (aidx.GetSize()>0)
630 {
631 pname += ";";
632 for (int i=0; i<aidx.GetSize(); i++)
633 pname += aidx[i];
634 }
635 }
636
637 TProfile *h1=0;
638
639 //check if histogram with identical name exist
640 TObject *h1obj = gROOT->FindObject(pname);
641 if (h1obj && h1obj->InheritsFrom("TProfile")) {
642 h1 = (TProfile*)h1obj;
643 h1->Reset();
644 }
645
646 if (!h1)
647 {
648
649 Double_t min = 0.;
650 Double_t max = fGeomCam->GetMaxRadius();
651
652 Int_t newbins=0;
653
654 THLimitsFinder::OptimizeLimits(nbins, newbins, min, max, kFALSE);
655
656 h1 = new TProfile(pname, GetTitle(), nbins, min, max);
657 h1->SetDirectory(pname.IsNull() ? NULL : gROOT);
658 h1->SetXTitle("Radius from camera center [mm]");
659 h1->SetYTitle(GetYaxis()->GetTitle());
660 }
661
662 // Fill the projected histogram
663 for (Int_t idx=0; idx<fNcells-2; idx++)
664 if (IsUsed(idx) && MatchSector(idx, sector, aidx))
665 h1->Fill(TMath::Hypot((*fGeomCam)[idx].GetX(),(*fGeomCam)[idx].GetY()),
666 GetBinContent(idx+1));
667 return h1;
668}
669
670
671// ------------------------------------------------------------------------
672//
673// Resizes the current pad so that the camera is displayed in its
674// correct aspect ratio
675//
676void MHCamera::SetRange()
677{
678 const Float_t range = fGeomCam->GetMaxRadius()*1.05;
679
680 //
681 // Maintain aspect ratio
682 //
683 const float ratio = TestBit(kNoLegend) ? 1 : 1.15;
684
685 //
686 // Calculate width and height of the current pad in pixels
687 //
688 Float_t w = gPad->GetWw();
689 Float_t h = gPad->GetWh()*ratio;
690
691 //
692 // This prevents the pad from resizing itself wrongly
693 //
694 if (gPad->GetMother() != gPad)
695 {
696 w *= gPad->GetMother()->GetAbsWNDC();
697 h *= gPad->GetMother()->GetAbsHNDC();
698 }
699
700 //
701 // Set Range (coordinate system) of pad
702 //
703 gPad->Range(-range, -range, (2*ratio-1)*range, range);
704
705 //
706 // Resize Pad to given ratio
707 //
708 if (h<w)
709 gPad->SetPad((1.-h/w)/2, 0, (h/w+1.)/2, 1);
710 else
711 gPad->SetPad(0, (1.-w/h)/2, 1, (w/h+1.)/2);
712}
713
714// ------------------------------------------------------------------------
715//
716// Updates the pixel colors and paints the pixels
717//
718void MHCamera::Update(Bool_t islog, Bool_t isbox, Bool_t iscol, Bool_t issame)
719{
720 Double_t min = GetMinimum(kFALSE);
721 Double_t max = GetMaximum(kFALSE);
722 if (min==FLT_MAX)
723 {
724 min = 0;
725 max = 1;
726 }
727
728 if (min==max)
729 max += 1;
730
731 if (!issame)
732 UpdateLegend(min, max, islog);
733
734 // Try to estimate the units of the current display. This is only
735 // necessary for 'same' option and allows distorted images of the camera!
736 const Float_t maxr = (1-fGeomCam->GetConvMm2Deg())*fGeomCam->GetMaxRadius()/2;
737 const Float_t conv = !issame ||
738 gPad->GetX1()<-maxr || gPad->GetY1()<-maxr ||
739 gPad->GetX2()> maxr || gPad->GetY2()>maxr ? 1 : fGeomCam->GetConvMm2Deg();
740
741 MHexagon hex;
742 for (Int_t i=0; i<fNcells-2; i++)
743 {
744 hex.SetFillStyle(issame ? 0 : 1001);
745
746 if (!issame)
747 {
748 if (IsUsed(i) && iscol)
749 {
750 if (TMath::IsNaN(fArray[i+1]))
751 gLog << warn << "MHCamera::Update: " << GetName() << " <" << GetTitle() << "> - Pixel Index #" << i << " contents is NaN (Not a Number)..." << endl;
752
753 hex.SetFillColor(GetColor(GetBinContent(i+1), min, max, islog));
754 }
755 else
756 hex.SetFillColor(10);
757 }
758
759 const MGeomPix &pix = (*fGeomCam)[i];
760
761 const Float_t x = pix.GetX()*conv;
762 const Float_t y = pix.GetY()*conv;
763 const Float_t d = pix.GetD()*conv;
764
765 if (!isbox)
766 hex.PaintHexagon(x, y, d);
767 else
768 if (IsUsed(i) && !TMath::IsNaN(fArray[i+1]))
769 {
770 Float_t size = d*(GetBinContent(i+1)-min)/(max-min);
771 if (size>d)
772 size=d;
773 hex.PaintHexagon(x, y, size);
774 }
775 }
776}
777
778// ------------------------------------------------------------------------
779//
780// Print minimum and maximum
781//
782void MHCamera::Print(Option_t *) const
783{
784 gLog << all << "Minimum: " << GetMinimum();
785 if (fMinimum==-1111)
786 gLog << " <autoscaled>";
787 gLog << endl;
788 gLog << "Maximum: " << GetMaximum();
789 if (fMaximum==-1111)
790 gLog << " <autoscaled>";
791 gLog << endl;
792}
793
794// ------------------------------------------------------------------------
795//
796// Paint the y-axis title
797//
798void MHCamera::PaintAxisTitle()
799{
800 const Float_t range = fGeomCam->GetMaxRadius()*1.05;
801 const Float_t w = (1 + 1.5/sqrt((float)(fNcells-2)))*range;
802
803 TLatex *ptitle = new TLatex(w, -.90*range, GetYaxis()->GetTitle());
804
805 ptitle->SetTextSize(0.05);
806 ptitle->SetTextAlign(21);
807
808 // box with the histogram title
809 ptitle->SetTextColor(gStyle->GetTitleTextColor());
810#if ROOT_VERSION_CODE > ROOT_VERSION(3,05,01)
811 ptitle->SetTextFont(gStyle->GetTitleFont(""));
812#endif
813 ptitle->Paint();
814}
815
816// ------------------------------------------------------------------------
817//
818// Paints the camera.
819//
820void MHCamera::Paint(Option_t *o)
821{
822 if (fNcells<=1)
823 return;
824
825 TString opt(o);
826 opt.ToLower();
827
828 if (opt.Contains("hist"))
829 {
830 opt.ReplaceAll("hist", "");
831 TH1D::Paint(opt);
832 return;
833 }
834
835 if (opt.Contains("proj"))
836 {
837 opt.ReplaceAll("proj", "");
838 Projection(GetName())->Paint(opt);
839 return;
840 }
841
842 const Bool_t hassame = opt.Contains("same");
843 const Bool_t hasbox = opt.Contains("box");
844 const Bool_t hascol = hasbox ? !opt.Contains("nocol") : kTRUE;
845
846 if (!hassame)
847 {
848 gPad->Clear();
849
850 // Maintain aspect ratio
851 SetRange();
852
853 if (GetPainter())
854 {
855 // Paint statistics
856 if (!TestBit(TH1::kNoStats))
857 fPainter->PaintStat(gStyle->GetOptStat(), NULL);
858
859 // Paint primitives (pixels, color legend, photons, ...)
860 if (fPainter->InheritsFrom(THistPainter::Class()))
861 {
862 static_cast<THistPainter*>(fPainter)->MakeChopt("");
863 static_cast<THistPainter*>(fPainter)->PaintTitle();
864 }
865 }
866 }
867
868 // Update Contents of the pixels and paint legend
869 Update(gPad->GetLogy(), hasbox, hascol, hassame);
870
871 if (!hassame)
872 PaintAxisTitle();
873
874 if (opt.Contains("pixelindex"))
875 PaintIndices(0);
876 if (opt.Contains("sectorindex"))
877 PaintIndices(1);
878 if (opt.Contains("content"))
879 PaintIndices(2);
880}
881
882// ------------------------------------------------------------------------
883//
884// With this function you can change the color palette. For more
885// information see TStyle::SetPalette. Only palettes with 50 colors
886// are allowed.
887// In addition you can use SetPalette(52, 0) to create an inverse
888// deep blue sea palette
889//
890void MHCamera::SetPalette(Int_t ncolors, Int_t *colors)
891{
892 //
893 // If not enough colors are specified skip this.
894 //
895 if (ncolors>1 && ncolors<50)
896 {
897 gLog << err << "MHCamera::SetPalette: Only default palettes with 50 colors are allowed... ignored." << endl;
898 return;
899 }
900
901 //
902 // If ncolors==52 create a reversed deep blue sea palette
903 //
904 if (ncolors==52)
905 {
906 gStyle->SetPalette(51, NULL);
907 TArrayI c(kItemsLegend);
908 for (int i=0; i<kItemsLegend; i++)
909 c[kItemsLegend-i-1] = gStyle->GetColorPalette(i);
910 gStyle->SetPalette(kItemsLegend, c.GetArray());
911 }
912 else
913 gStyle->SetPalette(ncolors, colors);
914
915 fColors.Set(kItemsLegend);
916 for (int i=0; i<kItemsLegend; i++)
917 fColors[i] = gStyle->GetColorPalette(i);
918}
919
920
921void MHCamera::SetPrettyPalette()
922{
923 if (!TString(GetDrawOption()).Contains("hist", TString::kIgnoreCase))
924 SetPalette(1, 0);
925}
926
927void MHCamera::SetDeepBlueSeaPalette()
928{
929 if (!TString(GetDrawOption()).Contains("hist", TString::kIgnoreCase))
930 SetPalette(51, 0);
931}
932
933void MHCamera::SetInvDeepBlueSeaPalette()
934{
935 if (!TString(GetDrawOption()).Contains("hist", TString::kIgnoreCase))
936 SetPalette(52, 0);
937}
938
939void MHCamera::PaintIndices(Int_t type)
940{
941 if (fNcells<=1)
942 return;
943
944 const Double_t min = GetMinimum();
945 const Double_t max = GetMaximum();
946
947 if (type==2 && max==min)
948 return;
949
950 TText txt;
951 txt.SetTextFont(122);
952 txt.SetTextAlign(22); // centered/centered
953
954 for (Int_t i=0; i<fNcells-2; i++)
955 {
956 const MGeomPix &h = (*fGeomCam)[i];
957
958 TString num;
959 switch (type)
960 {
961 case 0: num += i; break;
962 case 1: num += h.GetSector(); break;
963 case 2: num += (Int_t)((fArray[i+1]-min)/(max-min)); break;
964 }
965
966 // FIXME: Should depend on the color of the pixel...
967 //(GetColor(GetBinContent(i+1), min, max, 0));
968 txt.SetTextColor(kRed);
969 txt.SetTextSize(0.3*h.GetD()/fGeomCam->GetMaxRadius()/1.05);
970 txt.PaintText(h.GetX(), h.GetY(), num);
971 }
972}
973
974// ------------------------------------------------------------------------
975//
976// Call this function to add a MCamEvent on top of the present contents.
977//
978void MHCamera::AddCamContent(const MCamEvent &event, Int_t type)
979{
980 if (fNcells<=1 || IsFreezed())
981 return;
982
983 // FIXME: Security check missing!
984 for (Int_t idx=0; idx<fNcells-2; idx++)
985 {
986 Double_t val=0;
987 if (event.GetPixelContent(val, idx, *fGeomCam, type)/* && !IsUsed(idx)*/)
988 SetUsed(idx);
989
990 Fill(idx, val); // FIXME: Slow!
991 }
992 fEntries++;
993}
994
995// ------------------------------------------------------------------------
996//
997// Call this function to add a MCamEvent on top of the present contents.
998//
999void MHCamera::SetCamError(const MCamEvent &evt, Int_t type)
1000{
1001
1002 if (fNcells<=1 || IsFreezed())
1003 return;
1004
1005 // FIXME: Security check missing!
1006 for (Int_t idx=0; idx<fNcells-2; idx++)
1007 {
1008 Double_t val=0;
1009 if (evt.GetPixelContent(val, idx, *fGeomCam, type)/* && !IsUsed(idx)*/)
1010 SetUsed(idx);
1011
1012 SetBinError(idx+1, val); // FIXME: Slow!
1013 }
1014}
1015
1016Stat_t MHCamera::GetBinError(Int_t bin) const
1017{
1018 Double_t rc = 0;
1019 if (TestBit(kVariance) && GetEntries()>0) // error on the mean
1020 {
1021 const Double_t error = fSumw2.fArray[bin]/GetEntries();
1022 const Double_t val = fArray[bin]/GetEntries();
1023 rc = TMath::Sqrt(error - val*val);
1024 }
1025 else
1026 {
1027 rc = TH1D::GetBinError(bin);
1028 rc = Profile(rc);
1029 }
1030
1031 return rc;
1032}
1033
1034// ------------------------------------------------------------------------
1035//
1036// Call this function to add a MHCamera on top of the present contents.
1037// Type:
1038// 0) bin content
1039// 1) errors
1040// 2) rel. errors
1041//
1042void MHCamera::AddCamContent(const MHCamera &d, Int_t type)
1043{
1044 if (fNcells!=d.fNcells || IsFreezed())
1045 return;
1046
1047 // FIXME: Security check missing!
1048 for (Int_t idx=0; idx<fNcells-2; idx++)
1049 if (d.IsUsed(idx))
1050 SetUsed(idx);
1051
1052 switch (type)
1053 {
1054 case 1:
1055 for (Int_t idx=0; idx<fNcells-2; idx++)
1056 Fill(idx, d.GetBinError(idx+1));
1057 break;
1058 case 2:
1059 for (Int_t idx=0; idx<fNcells-2; idx++)
1060 if (d.GetBinContent(idx+1)!=0)
1061 Fill(idx, TMath::Abs(d.GetBinError(idx+1)/d.GetBinContent(idx+1)));
1062 break;
1063 default:
1064 for (Int_t idx=0; idx<fNcells-2; idx++)
1065 Fill(idx, d.GetBinContent(idx+1));
1066 break;
1067 }
1068 fEntries++;
1069}
1070
1071// ------------------------------------------------------------------------
1072//
1073// Call this function to add a TArrayD on top of the present contents.
1074//
1075void MHCamera::AddCamContent(const TArrayD &event, const TArrayC *used)
1076{
1077 if (event.GetSize()!=fNcells-2 || IsFreezed())
1078 return;
1079
1080 if (used && used->GetSize()!=fNcells-2)
1081 return;
1082
1083 for (Int_t idx=0; idx<fNcells-2; idx++)
1084 {
1085 Fill(idx, const_cast<TArrayD&>(event)[idx]); // FIXME: Slow!
1086
1087 if (!used || (*const_cast<TArrayC*>(used))[idx])
1088 SetUsed(idx);
1089 }
1090 fEntries++;
1091}
1092
1093// ------------------------------------------------------------------------
1094//
1095// Call this function to add a MCamEvent on top of the present contents.
1096// 1 is added to each pixel if the contents of MCamEvent>threshold
1097//
1098void MHCamera::CntCamContent(const MCamEvent &event, Double_t threshold, Int_t type)
1099{
1100 if (fNcells<=1 || IsFreezed())
1101 return;
1102
1103 // FIXME: Security check missing!
1104 for (Int_t idx=0; idx<fNcells-2; idx++)
1105 {
1106 Double_t val=threshold;
1107 if (event.GetPixelContent(val, idx, *fGeomCam, type)/* && !IsUsed(idx)*/)
1108 SetUsed(idx);
1109
1110 if (val>threshold)
1111 Fill(idx);
1112 }
1113 fEntries++;
1114}
1115
1116// ------------------------------------------------------------------------
1117//
1118// Call this function to add a TArrayD on top of the present contents.
1119// 1 is added to each pixel if the contents of MCamEvent>threshold
1120//
1121void MHCamera::CntCamContent(const TArrayD &event, Double_t threshold, Bool_t ispos)
1122{
1123 if (event.GetSize()!=fNcells-2 || IsFreezed())
1124 return;
1125
1126 for (Int_t idx=0; idx<fNcells-2; idx++)
1127 {
1128 if (const_cast<TArrayD&>(event)[idx]>threshold)
1129 Fill(idx);
1130
1131 if (!ispos || fArray[idx+1]>0)
1132 SetUsed(idx);
1133 }
1134 fEntries++;
1135}
1136
1137// ------------------------------------------------------------------------
1138//
1139// Fill the pixels with random contents.
1140//
1141void MHCamera::FillRandom()
1142{
1143 if (fNcells<=1 || IsFreezed())
1144 return;
1145
1146 Reset();
1147
1148 // FIXME: Security check missing!
1149 for (Int_t idx=0; idx<fNcells-2; idx++)
1150 {
1151 Fill(idx, gRandom->Uniform()*fGeomCam->GetPixRatio(idx));
1152 SetUsed(idx);
1153 }
1154 fEntries=1;
1155}
1156
1157
1158// ------------------------------------------------------------------------
1159//
1160// The array must be in increasing order, eg: 2.5, 3.7, 4.9
1161// The values in each bin are replaced by the interval in which the value
1162// fits. In the example we have four intervals
1163// (<2.5, 2.5-3.7, 3.7-4.9, >4.9). Maximum and minimum are set
1164// accordingly.
1165//
1166void MHCamera::SetLevels(const TArrayF &arr)
1167{
1168 if (fNcells<=1)
1169 return;
1170
1171 for (Int_t i=0; i<fNcells-2; i++)
1172 {
1173 if (!IsUsed(i))
1174 continue;
1175
1176 Int_t j = arr.GetSize();
1177 while (j && fArray[i+1]<arr[j-1])
1178 j--;
1179
1180 fArray[i+1] = j;
1181 }
1182 SetMaximum(arr.GetSize());
1183 SetMinimum(0);
1184}
1185
1186// ------------------------------------------------------------------------
1187//
1188// Reset the all pixel colors to a default value
1189//
1190void MHCamera::Reset(Option_t *opt)
1191{
1192 if (fNcells<=1 || IsFreezed())
1193 return;
1194
1195 TH1::Reset(opt);
1196
1197 for (Int_t i=0; i<fNcells-2; i++)
1198 {
1199 fArray[i+1]=0;
1200 ResetUsed(i);
1201 }
1202 fArray[0] = 0;
1203 fArray[fNcells-1] = 0;
1204}
1205
1206// ------------------------------------------------------------------------
1207//
1208// Here we calculate the color index for the current value.
1209// The color index is defined with the class TStyle and the
1210// Color palette inside. We use the command gStyle->SetPalette(1,0)
1211// for the display. So we have to convert the value "wert" into
1212// a color index that fits the color palette.
1213// The range of the color palette is defined by the values fMinPhe
1214// and fMaxRange. Between this values we have 50 color index, starting
1215// with 0 up to 49.
1216//
1217Int_t MHCamera::GetColor(Float_t val, Float_t min, Float_t max, Bool_t islog)
1218{
1219 if (TMath::IsNaN(val)) // FIXME: gLog!
1220 return 10;
1221
1222 //
1223 // first treat the over- and under-flows
1224 //
1225 const Int_t maxcolidx = kItemsLegend-1;
1226
1227 if (val >= max)
1228 return fColors[maxcolidx];
1229
1230 if (val <= min)
1231 return fColors[0];
1232
1233 //
1234 // calculate the color index
1235 //
1236 Float_t ratio;
1237 if (islog && min>0)
1238 ratio = log10(val/min) / log10(max/min);
1239 else
1240 ratio = (val-min) / (max-min);
1241
1242 const Int_t colidx = (Int_t)(ratio*maxcolidx + .5);
1243 return fColors[colidx];
1244}
1245
1246TPaveStats *MHCamera::GetStatisticBox()
1247{
1248 TObject *obj = 0;
1249
1250 TIter Next(fFunctions);
1251 while ((obj = Next()))
1252 if (obj->InheritsFrom(TPaveStats::Class()))
1253 return static_cast<TPaveStats*>(obj);
1254
1255 return NULL;
1256}
1257
1258// ------------------------------------------------------------------------
1259//
1260// Change the text on the legend according to the range of the Display
1261//
1262void MHCamera::UpdateLegend(Float_t min, Float_t max, Bool_t islog)
1263{
1264 const Float_t range = fGeomCam->GetMaxRadius()*1.05;
1265
1266 TArrow arr;
1267 arr.PaintArrow(-range*.9, -range*.9, -range*.6, -range*.9, 0.025);
1268 arr.PaintArrow(-range*.9, -range*.9, -range*.9, -range*.6, 0.025);
1269
1270 TString text;
1271 text += (int)(range*.3);
1272 text += "mm";
1273
1274 TText newtxt2;
1275 newtxt2.SetTextSize(0.04);
1276 newtxt2.PaintText(-range*.85, -range*.85, text);
1277
1278 text = "";
1279 text += (float)((int)(range*.3*fGeomCam->GetConvMm2Deg()*10))/10;
1280 text += "\\circ";
1281 text = text.Strip(TString::kLeading);
1282
1283 TLatex latex;
1284 latex.PaintLatex(-range*.85, -range*.75, 0, 0.04, text);
1285
1286 if (TestBit(kNoLegend))
1287 return;
1288
1289 TPaveStats *stats = GetStatisticBox();
1290
1291 const Float_t hndc = 0.92 - (stats ? stats->GetY1NDC() : 1);
1292 const Float_t H = (0.75-hndc)*range;
1293 const Float_t offset = hndc*range;
1294
1295 const Float_t h = 2./kItemsLegend;
1296 const Float_t w = range/sqrt((float)(fNcells-2));
1297
1298 TBox newbox;
1299 TText newtxt;
1300 newtxt.SetTextSize(0.03);
1301 newtxt.SetTextAlign(12);
1302#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
1303 newtxt.SetBit(/*kNoContextMenu|*/kCannotPick);
1304 newbox.SetBit(/*kNoContextMenu|*/kCannotPick);
1305#endif
1306
1307 const Float_t step = (islog && min>0 ? log10(max/min) : max-min) / kItemsLegend;
1308 const Int_t firsts = step*3 < 1e-8 ? 8 : (Int_t)floor(log10(step*3));
1309 const TString opt = Form("%%.%if", firsts>0 ? 0 : TMath::Abs(firsts));
1310
1311 for (Int_t i=0; i<kItemsLegend+1; i+=3)
1312 {
1313 Float_t val;
1314 if (islog && min>0)
1315 val = pow(10, step*i) * min;
1316 else
1317 val = min + step*i;
1318
1319 //const bool dispexp = max-min>1.5 && fabs(val)>0.1 && fabs(val)<1e6;
1320 newtxt.PaintText(range+1.5*w, H*(i*h-1)-offset, Form(opt, val));
1321 }
1322
1323 for (Int_t i=0; i<kItemsLegend; i++)
1324 {
1325 newbox.SetFillColor(fColors[i]);
1326 newbox.PaintBox(range, H*(i*h-1)-offset, range+w, H*((i+1)*h-1)-offset);
1327 }
1328}
1329
1330// ------------------------------------------------------------------------
1331//
1332// Save primitive as a C++ statement(s) on output stream out
1333//
1334void MHCamera::SavePrimitive(ofstream &out, Option_t *opt)
1335{
1336 gLog << err << "MHCamera::SavePrimitive: Must be rewritten!" << endl;
1337 /*
1338 if (!gROOT->ClassSaved(TCanvas::Class()))
1339 fDrawingPad->SavePrimitive(out, opt);
1340
1341 out << " " << fDrawingPad->GetName() << "->SetWindowSize(";
1342 out << fDrawingPad->GetWw() << "," << fDrawingPad->GetWh() << ");" << endl;
1343 */
1344}
1345
1346// ------------------------------------------------------------------------
1347//
1348// compute the distance of a point (px,py) to the Camera
1349// this functions needed for graphical primitives, that
1350// means without this function you are not able to interact
1351// with the graphical primitive with the mouse!!!
1352//
1353// All calcutations are done in pixel coordinates
1354//
1355Int_t MHCamera::DistancetoPrimitive(Int_t px, Int_t py)
1356{
1357 if (fNcells<=1)
1358 return 999999;
1359
1360 TPaveStats *box = (TPaveStats*)gPad->GetPrimitive("stats");
1361 if (box)
1362 {
1363 const Double_t w = box->GetY2NDC()-box->GetY1NDC();
1364 box->SetX1NDC(gStyle->GetStatX()-gStyle->GetStatW());
1365 box->SetY1NDC(gStyle->GetStatY()-w);
1366 box->SetX2NDC(gStyle->GetStatX());
1367 box->SetY2NDC(gStyle->GetStatY());
1368 }
1369
1370 if (TString(GetDrawOption()).Contains("hist", TString::kIgnoreCase))
1371 return TH1D::DistancetoPrimitive(px, py);
1372
1373 const Bool_t issame = TString(GetDrawOption()).Contains("same", TString::kIgnoreCase);
1374
1375 const Float_t maxr = (1-fGeomCam->GetConvMm2Deg())*fGeomCam->GetMaxRadius()/2;
1376 const Float_t conv = !issame ||
1377 gPad->GetX1()<-maxr || gPad->GetY1()<-maxr ||
1378 gPad->GetX2()> maxr || gPad->GetY2()>maxr ? 1 : fGeomCam->GetConvMm2Deg();
1379
1380 if (GetPixelIndex(px, py, conv)>=0)
1381 return 0;
1382
1383 if (!box)
1384 return 999999;
1385
1386 const Int_t dist = box->DistancetoPrimitive(px, py);
1387 if (dist > TPad::GetMaxPickDistance())
1388 return 999999;
1389
1390 gPad->SetSelected(box);
1391 return dist;
1392}
1393
1394// ------------------------------------------------------------------------
1395//
1396//
1397Int_t MHCamera::GetPixelIndex(Int_t px, Int_t py, Float_t conv) const
1398{
1399 if (fNcells<=1)
1400 return -1;
1401
1402 Int_t i;
1403 for (i=0; i<fNcells-2; i++)
1404 {
1405 MHexagon hex((*fGeomCam)[i]);
1406 if (hex.DistancetoPrimitive(px, py, conv)>0)
1407 continue;
1408
1409 return i;
1410 }
1411 return -1;
1412}
1413
1414// ------------------------------------------------------------------------
1415//
1416// Returns string containing info about the object at position (px,py).
1417// Returned string will be re-used (lock in MT environment).
1418//
1419char *MHCamera::GetObjectInfo(Int_t px, Int_t py) const
1420{
1421 if (TString(GetDrawOption()).Contains("hist", TString::kIgnoreCase))
1422 return TH1D::GetObjectInfo(px, py);
1423
1424 static char info[128];
1425
1426 const Int_t idx=GetPixelIndex(px, py);
1427
1428 if (idx<0)
1429 return TObject::GetObjectInfo(px, py);
1430
1431 sprintf(info, "Software Pixel Index: %d (Hardware Id=%d)", idx, idx+1);
1432 return info;
1433}
1434
1435// ------------------------------------------------------------------------
1436//
1437// Add a MCamEvent which should be displayed when the user clicks on a
1438// pixel.
1439// Warning: The object MUST inherit from TObject AND MCamEvent
1440//
1441void MHCamera::AddNotify(TObject *obj)
1442{
1443 // Make sure, that the object derives from MCamEvent!
1444 MCamEvent *evt = dynamic_cast<MCamEvent*>(obj);
1445 if (!evt)
1446 {
1447 gLog << err << "ERROR: MHCamera::AddNotify - TObject doesn't inherit from MCamEvent... ignored." << endl;
1448 return;
1449 }
1450
1451 // Make sure, that it is deleted from the list too, if the obj is deleted
1452 obj->SetBit(kMustCleanup);
1453
1454 // Add object to list
1455 fNotify->Add(obj);
1456}
1457
1458// ------------------------------------------------------------------------
1459//
1460// Execute a mouse event on the camera
1461//
1462void MHCamera::ExecuteEvent(Int_t event, Int_t px, Int_t py)
1463{
1464 if (TString(GetDrawOption()).Contains("hist", TString::kIgnoreCase))
1465 {
1466 TH1D::ExecuteEvent(event, px, py);
1467 return;
1468 }
1469 //if (event==kMouseMotion && fStatusBar)
1470 // fStatusBar->SetText(GetObjectInfo(px, py), 0);
1471 if (event!=kButton1Down)
1472 return;
1473
1474 const Int_t idx = GetPixelIndex(px, py);
1475 if (idx<0)
1476 return;
1477
1478 gLog << all << GetTitle() << " <" << GetName() << ">" << endl;
1479 gLog << "Software Pixel Idx: " << idx << endl;
1480 gLog << "Hardware Pixel Id: " << idx+1 << endl;
1481 gLog << "Contents: " << GetBinContent(idx+1);
1482 if (GetBinError(idx+1)>0)
1483 gLog << " +/- " << GetBinError(idx+1);
1484 gLog << " <" << (IsUsed(idx)?"on":"off") << ">" << endl;
1485
1486 if (fNotify && fNotify->GetSize()>0)
1487 {
1488 // FIXME: Is there a simpler and more convinient way?
1489
1490 // The name which is created here depends on the instance of
1491 // MHCamera and on the pad on which it is drawn --> The name
1492 // is unique. For ExecuteEvent gPad is always correctly set.
1493 const TString name = Form("%p;%p;PixelContent", this, gPad);
1494
1495 TCanvas *old = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(name);
1496 if (old)
1497 old->cd();
1498 else
1499 new TCanvas(name);
1500
1501 /*
1502 TIter Next(gPad->GetListOfPrimitives());
1503 TObject *o;
1504 while (o=Next()) cout << o << ": " << o->GetName() << " " << o->IsA()->GetName() << endl;
1505 */
1506
1507 // FIXME: Make sure, that the old histograms are really deleted.
1508 // Are they already deleted?
1509
1510 // The dynamic_cast is necessary here: We cannot use ForEach
1511 TIter Next(fNotify);
1512 MCamEvent *evt;
1513 while ((evt=dynamic_cast<MCamEvent*>(Next())))
1514 evt->DrawPixelContent(idx);
1515
1516 gPad->Modified();
1517 gPad->Update();
1518 }
1519}
1520
1521UInt_t MHCamera::GetNumPixels() const
1522{
1523 return fGeomCam->GetNumPixels();
1524}
1525
1526TH1 *MHCamera::DrawCopy() const
1527{
1528 gPad=NULL;
1529 return TH1D::DrawCopy(fName+";cpy");
1530}
1531
1532
1533// --------------------------------------------------------------------------
1534//
1535// Draw a projection of MHCamera onto the y-axis values. Depending on the
1536// variable fit, the following fits are performed:
1537//
1538// 0: No fit, simply draw the projection
1539// 1: Single Gauss (for distributions flat-fielded over the whole camera)
1540// 2: Double Gauss (for distributions different for inner and outer pixels)
1541// 3: Triple Gauss (for distributions with inner, outer pixels and outliers)
1542// 4: flat (for the probability distributions)
1543// (1-4:) Moreover, sectors 6,1 and 2 of the camera and sectors 3,4 and 5 are
1544// drawn separately, for inner and outer pixels.
1545// 5: Fit Inner and Outer pixels separately by a single Gaussian
1546// (only for MAGIC cameras)
1547// 6: Fit Inner and Outer pixels separately by a single Gaussian and display
1548// additionally the two camera halfs separately (for MAGIC camera)
1549//
1550//
1551void MHCamera::DrawProjection(Int_t fit) const
1552{
1553
1554 TArrayI inner(1);
1555 inner[0] = 0;
1556
1557 TArrayI outer(1);
1558 outer[0] = 1;
1559
1560 if (fit==5 || fit==6)
1561 {
1562
1563 if (GetGeomCam().InheritsFrom("MGeomCamMagic"))
1564 {
1565 TArrayI s0(6);
1566 s0[0] = 6;
1567 s0[1] = 1;
1568 s0[2] = 2;
1569 s0[3] = 3;
1570 s0[4] = 4;
1571 s0[5] = 5;
1572
1573 TArrayI s1(3);
1574 s1[0] = 6;
1575 s1[1] = 1;
1576 s1[2] = 2;
1577
1578 TArrayI s2(3);
1579 s2[0] = 3;
1580 s2[1] = 4;
1581 s2[2] = 5;
1582
1583 gPad->Clear();
1584 TVirtualPad *pad = gPad;
1585 pad->Divide(2,1);
1586
1587 TH1D *inout[2];
1588 inout[0] = ProjectionS(s0, inner, "Inner");
1589 inout[1] = ProjectionS(s0, outer, "Outer");
1590
1591 inout[0]->SetDirectory(NULL);
1592 inout[1]->SetDirectory(NULL);
1593
1594 for (int i=0; i<2; i++)
1595 {
1596 pad->cd(i+1);
1597 inout[i]->SetLineColor(kRed+i);
1598 inout[i]->SetBit(kCanDelete);
1599 inout[i]->Draw();
1600 inout[i]->Fit("gaus","Q");
1601
1602 if (fit == 6)
1603 {
1604 TH1D *half[2];
1605 half[0] = ProjectionS(s1, i==0 ? inner : outer , "Sector 6-1-2");
1606 half[1] = ProjectionS(s2, i==0 ? inner : outer , "Sector 3-4-5");
1607
1608 for (int j=0; j<2; j++)
1609 {
1610 half[j]->SetLineColor(kRed+i+2*j);
1611 half[j]->SetDirectory(0);
1612 half[j]->SetBit(kCanDelete);
1613 half[j]->Draw("same");
1614 }
1615 }
1616
1617 }
1618
1619 gLog << all << GetName()
1620 << Form("%s%5.3f%s%3.2f"," Mean: Inner Pixels: ",
1621 inout[0]->GetFunction("gaus")->GetParameter(1),"+-",
1622 inout[0]->GetFunction("gaus")->GetParError(1));
1623 gLog << Form("%s%5.3f%s%3.2f"," Outer Pixels: ",
1624 inout[1]->GetFunction("gaus")->GetParameter(1),"+-",
1625 inout[1]->GetFunction("gaus")->GetParError(1)) << endl;
1626 gLog << all << GetName()
1627 << Form("%s%5.3f%s%3.2f"," Sigma: Inner Pixels: ",
1628 inout[0]->GetFunction("gaus")->GetParameter(2),"+-",
1629 inout[0]->GetFunction("gaus")->GetParError(2));
1630 gLog << Form("%s%5.3f%s%3.2f"," Outer Pixels: ",
1631 inout[1]->GetFunction("gaus")->GetParameter(2),"+-",
1632 inout[1]->GetFunction("gaus")->GetParError(2)) << endl;
1633
1634 }
1635 return;
1636 }
1637
1638 TH1D *obj2 = (TH1D*)Projection(GetName());
1639 obj2->SetDirectory(0);
1640 obj2->Draw();
1641 obj2->SetBit(kCanDelete);
1642
1643 if (fit == 0)
1644 return;
1645
1646 if (GetGeomCam().InheritsFrom("MGeomCamMagic"))
1647 {
1648 TArrayI s0(3);
1649 s0[0] = 6;
1650 s0[1] = 1;
1651 s0[2] = 2;
1652
1653 TArrayI s1(3);
1654 s1[0] = 3;
1655 s1[1] = 4;
1656 s1[2] = 5;
1657
1658
1659 TH1D *halfInOut[4];
1660
1661 // Just to get the right (maximum) binning
1662 halfInOut[0] = ProjectionS(s0, inner, "Sector 6-1-2 Inner");
1663 halfInOut[1] = ProjectionS(s1, inner, "Sector 3-4-5 Inner");
1664 halfInOut[2] = ProjectionS(s0, outer, "Sector 6-1-2 Outer");
1665 halfInOut[3] = ProjectionS(s1, outer, "Sector 3-4-5 Outer");
1666
1667 for (int i=0; i<4; i++)
1668 {
1669 halfInOut[i]->SetLineColor(kRed+i);
1670 halfInOut[i]->SetDirectory(0);
1671 halfInOut[i]->SetBit(kCanDelete);
1672 halfInOut[i]->Draw("same");
1673 }
1674 }
1675
1676 const Double_t min = obj2->GetBinCenter(obj2->GetXaxis()->GetFirst());
1677 const Double_t max = obj2->GetBinCenter(obj2->GetXaxis()->GetLast());
1678 const Double_t integ = obj2->Integral("width")/2.5;
1679 const Double_t mean = obj2->GetMean();
1680 const Double_t rms = obj2->GetRMS();
1681 const Double_t width = max-min;
1682
1683 const TString dgausformula = "([0]-[3])/[2]*exp(-0.5*(x-[1])*(x-[1])/[2]/[2])"
1684 "+[3]/[5]*exp(-0.5*(x-[4])*(x-[4])/[5]/[5])";
1685
1686 const TString tgausformula = "([0]-[3]-[6])/[2]*exp(-0.5*(x-[1])*(x-[1])/[2]/[2])"
1687 "+[3]/[5]*exp(-0.5*(x-[4])*(x-[4])/[5]/[5])"
1688 "+[6]/[8]*exp(-0.5*(x-[7])*(x-[7])/[8]/[8])";
1689 TF1 *f=0;
1690 switch (fit)
1691 {
1692 case 1:
1693 f = new TF1("sgaus", "gaus(0)", min, max);
1694 f->SetLineColor(kYellow);
1695 f->SetBit(kCanDelete);
1696 f->SetParNames("Area", "#mu", "#sigma");
1697 f->SetParameters(integ/rms, mean, rms);
1698 f->SetParLimits(0, 0, integ);
1699 f->SetParLimits(1, min, max);
1700 f->SetParLimits(2, 0, width/1.5);
1701
1702 obj2->Fit(f, "QLR");
1703 break;
1704
1705 case 2:
1706 f = new TF1("dgaus",dgausformula.Data(),min,max);
1707 f->SetLineColor(kYellow);
1708 f->SetBit(kCanDelete);
1709 f->SetParNames("A_{tot}", "#mu1", "#sigma1", "A2", "#mu2", "#sigma2");
1710 f->SetParameters(integ,(min+mean)/2.,width/4.,
1711 integ/width/2.,(max+mean)/2.,width/4.);
1712 // The left-sided Gauss
1713 f->SetParLimits(0,integ-1.5 , integ+1.5);
1714 f->SetParLimits(1,min+(width/10.), mean);
1715 f->SetParLimits(2,0 , width/2.);
1716 // The right-sided Gauss
1717 f->SetParLimits(3,0 , integ);
1718 f->SetParLimits(4,mean, max-(width/10.));
1719 f->SetParLimits(5,0 , width/2.);
1720 obj2->Fit(f,"QLRM");
1721 break;
1722
1723 case 3:
1724 f = new TF1("tgaus",tgausformula.Data(),min,max);
1725 f->SetLineColor(kYellow);
1726 f->SetBit(kCanDelete);
1727 f->SetParNames("A_{tot}","#mu_{1}","#sigma_{1}",
1728 "A_{2}","#mu_{2}","#sigma_{2}",
1729 "A_{3}","#mu_{3}","#sigma_{3}");
1730 f->SetParameters(integ,(min+mean)/2,width/4.,
1731 integ/width/3.,(max+mean)/2.,width/4.,
1732 integ/width/3.,mean,width/2.);
1733 // The left-sided Gauss
1734 f->SetParLimits(0,integ-1.5,integ+1.5);
1735 f->SetParLimits(1,min+(width/10.),mean);
1736 f->SetParLimits(2,width/15.,width/2.);
1737 // The right-sided Gauss
1738 f->SetParLimits(3,0.,integ);
1739 f->SetParLimits(4,mean,max-(width/10.));
1740 f->SetParLimits(5,width/15.,width/2.);
1741 // The Gauss describing the outliers
1742 f->SetParLimits(6,0.,integ);
1743 f->SetParLimits(7,min,max);
1744 f->SetParLimits(8,width/4.,width/1.5);
1745 obj2->Fit(f,"QLRM");
1746 break;
1747
1748 case 4:
1749 obj2->Fit("pol0", "Q");
1750 obj2->GetFunction("pol0")->SetLineColor(kYellow);
1751 break;
1752
1753 case 9:
1754 break;
1755
1756 default:
1757 obj2->Fit("gaus", "Q");
1758 obj2->GetFunction("gaus")->SetLineColor(kYellow);
1759 break;
1760 }
1761}
1762
1763
1764// --------------------------------------------------------------------------
1765//
1766// Draw a projection of MHCamera vs. the radius from the central pixel.
1767//
1768// The inner and outer pixels are drawn separately, both fitted by a polynomial
1769// of grade 1.
1770//
1771void MHCamera::DrawRadialProfile() const
1772{
1773
1774 TProfile *obj2 = (TProfile*)RadialProfile(GetName());
1775 obj2->SetDirectory(0);
1776 obj2->Draw();
1777 obj2->SetBit(kCanDelete);
1778
1779 if (GetGeomCam().InheritsFrom("MGeomCamMagic"))
1780 {
1781
1782 TArrayI s0(6);
1783 s0[0] = 1;
1784 s0[1] = 2;
1785 s0[2] = 3;
1786 s0[3] = 4;
1787 s0[4] = 5;
1788 s0[5] = 6;
1789
1790 TArrayI inner(1);
1791 inner[0] = 0;
1792
1793 TArrayI outer(1);
1794 outer[0] = 1;
1795
1796 // Just to get the right (maximum) binning
1797 TProfile *half[2];
1798 half[0] = RadialProfileS(s0, inner,Form("%s%s",GetName(),"Inner"));
1799 half[1] = RadialProfileS(s0, outer,Form("%s%s",GetName(),"Outer"));
1800
1801 for (Int_t i=0; i<2; i++)
1802 {
1803 Double_t min = GetGeomCam().GetMinRadius(i);
1804 Double_t max = GetGeomCam().GetMaxRadius(i);
1805
1806 half[i]->SetLineColor(kRed+i);
1807 half[i]->SetDirectory(0);
1808 half[i]->SetBit(kCanDelete);
1809 half[i]->Draw("same");
1810 half[i]->Fit("pol1","Q","",min,max);
1811 half[i]->GetFunction("pol1")->SetLineColor(kRed+i);
1812 half[i]->GetFunction("pol1")->SetLineWidth(1);
1813 }
1814 }
1815}
1816
Note: See TracBrowser for help on using the repository browser.