o add Reset function to CalPad and CalROC o Add functionality to AliTPCdataQA - Reset...
[u/mrichter/AliRoot.git] / MUON / AliMUONPad.cxx
1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 *                                                                        *
4 * Author: The ALICE Off-line Project.                                    *
5 * Contributors are mentioned in the code where appropriate.              *
6 *                                                                        *
7 * Permission to use, copy, modify and distribute this software and its   *
8 * documentation strictly for non-commercial purposes is hereby granted   *
9 * without fee, provided that the above copyright notice appears in all   *
10 * copies and that both the copyright notice and this permission notice   *
11 * appear in the supporting documentation. The authors make no claims     *
12 * about the suitability of this software for any purpose. It is          *
13 * provided "as is" without express or implied warranty.                  *
14 **************************************************************************/
15
16 // $Id$
17
18 #include "AliMUONPad.h"
19
20 #include "AliLog.h"
21 #include "AliMpArea.h"
22
23 #include "Riostream.h"
24 #include "TVirtualPad.h"
25 #include "TVirtualX.h"
26 #include "TVector2.h"
27 #include "TMath.h"
28
29 //-----------------------------------------------------------------------------
30 /// \class AliMUONPad
31 ///
32 /// Object gathering information about a hit pad.
33 /// 
34 /// Can be seen as a combination of a Digit (which brings the charge) 
35 /// and an MpPad (which brings location and position)
36 ///
37 /// Also provided are some static functions to compute overlap and
38 /// get neighboring information.
39 ///
40 /// \author Laurent Aphecetche
41 //-----------------------------------------------------------------------------
42
43 using std::setw;
44 using std::cout;
45 using std::endl;
46 using std::ios_base;
47 using std::cerr;
48 using std::ios;
49 /// \cond CLASSIMP
50 ClassImp(AliMUONPad)
51 /// \endcond
52
53 namespace
54 {
55   AliMpArea
56   Intersect(const AliMpArea& a, const AliMpArea& b)
57   { 
58     //
59     // Returns the common part of a and b.
60     //
61     Double_t xmin = TMath::Max(a.LeftBorder(),b.LeftBorder());
62     Double_t xmax = TMath::Min(a.RightBorder(),b.RightBorder());
63     Double_t ymin = TMath::Max(a.DownBorder(),b.DownBorder());
64     Double_t ymax = TMath::Min(a.UpBorder(),b.UpBorder());
65     AliMpArea c( (xmin+xmax)/2.0, (ymin+ymax)/2.0 ,
66                  (xmax-xmin)/2.0, (ymax-ymin)/2.0 );
67         
68     return c;
69   }
70 }
71
72 //_____________________________________________________________________________
73 AliMUONPad::AliMUONPad()
74 :
75 TObject(),
76 fIsSaturated(kFALSE),
77 fIsReal(kFALSE),
78 fClusterId(-1),
79 fCathode(-1),
80 fDetElemId(-1),
81 fIx(-1),
82 fIy(-1),
83 fStatus(0),
84 fDimensions(),
85 fPosition(),
86 fCharge(0.0),
87 fChargeBackup(0.0)
88 {
89   /// Default ctor
90   Init(-1,-1,-1,-1,TVector2(0,0),TVector2(0,0),0);
91 }
92
93 //_____________________________________________________________________________
94 AliMUONPad::AliMUONPad(Int_t detElemId, Int_t cathode,
95                        Int_t ix, Int_t iy, Double_t x, Double_t y,
96                        Double_t dx, Double_t dy, Double_t charge)
97 :
98 TObject(),
99 fIsSaturated(kFALSE),
100 fIsReal(kFALSE),
101 fClusterId(-1),
102 fCathode(-1),
103 fDetElemId(-1),
104 fIx(-1),
105 fIy(-1),
106 fStatus(0),
107 fDimensions(),
108 fPosition(),
109 fCharge(0.0),
110 fChargeBackup(0.0)
111
112 {
113   /// Normal ctor, using full information
114   Init(detElemId,cathode,ix,iy,TVector2(x,y),TVector2(dx,dy),charge);
115 }
116
117 //_____________________________________________________________________________
118 AliMUONPad::AliMUONPad(Double_t x, Double_t y,
119                        Double_t dx, Double_t dy, Double_t charge)
120 : TObject(),
121 fIsSaturated(kFALSE),
122 fIsReal(kFALSE),
123 fClusterId(-1),
124 fCathode(-1),
125 fDetElemId(-1),
126 fIx(-1),
127 fIy(-1),
128 fStatus(0),
129 fDimensions(),
130 fPosition(),
131 fCharge(0.0),
132 fChargeBackup(0.0)
133 {
134   /// Truncated constructor (w/o DE, cath, ix, iy)
135   Init(-1,-1,-1,-1,TVector2(x,y),TVector2(dx,dy),charge);
136 }
137
138 //_____________________________________________________________________________
139 AliMUONPad::AliMUONPad(const TVector2& position, const TVector2& dimensions,
140                        Double_t charge)
141 : TObject(),
142 fIsSaturated(kFALSE),
143 fIsReal(kFALSE),
144 fClusterId(-1),
145 fCathode(-1),
146 fDetElemId(-1),
147 fIx(-1),
148 fIy(-1),
149 fStatus(0),
150 fDimensions(),
151 fPosition(),
152 fCharge(0.0),
153 fChargeBackup(0.0)
154 {
155   /// Alternate ctor
156   Init(-1,-1,-1,-1,position,dimensions,charge);
157 }
158
159 //_____________________________________________________________________________
160 AliMUONPad::~AliMUONPad()
161 {
162 /// Dtor
163 }
164
165 //_____________________________________________________________________________
166 Bool_t 
167 AliMUONPad::AreNeighbours(const AliMUONPad& d1, const AliMUONPad& d2) 
168 {
169   /// Whether 2 pads are neighbours or not
170   if ( d1.DetElemId() != d2.DetElemId() || 
171        d1.Cathode() != d2.Cathode() )
172   {
173     return kFALSE;
174   }
175   else
176   {
177     static Double_t precision = 1E-4; // cm
178     static TVector2 precisionAdjustment(-precision,-precision);    
179     return AreOverlapping(d1,d2,precisionAdjustment);
180   }
181 }
182
183 //_____________________________________________________________________________
184 Bool_t
185 AliMUONPad::AreOverlapping(const AliMUONPad& d1, const AliMUONPad& d2,
186                            const TVector2& precision)
187 {
188   /// Checks the overlap between 2 pads.
189   /// The actual overlap is computed not on d1 and d2, but on d1 and d2
190   /// "re-scaled" using the precision vector (conceptually equivalent to 
191   /// d.Dimensions() += precision)
192   ///
193   /// So, if the elements (x,y) of precision are :
194   ///
195   /// - positive, the overlap is "computed" from smaller d1 and d2  
196   ///   which is, modulo the precision, what you would think as a normal
197   ///   overlap calculation
198   /// - negative, overlap is from "bigger" d1 and d2, which is usefull to "tweek"
199   ///   what we call an overlap, e.g. to consider 2 pads touching only by their
200   ///   corners to be overlapping.
201   
202   AliMpArea a1(d1.X(),d1.Y(),d1.DX(),d1.DY());
203   AliMpArea a2(d2.X(),d2.Y(),d2.DX(),d2.DY());
204   
205   if ( a1.LeftBorder() > a2.RightBorder() - precision.X() ||
206        a1.RightBorder() < a2.LeftBorder() + precision.X() )
207   {
208     return kFALSE;
209   }
210   
211   if ( a1.DownBorder() > a2.UpBorder() - precision.Y() ||
212        a1.UpBorder() < a2.DownBorder() + precision.Y() )
213   {
214     return kFALSE;
215   }
216   return kTRUE;
217 }
218
219 //_____________________________________________________________________________
220 Bool_t
221 AliMUONPad::AreOverlapping(const AliMUONPad& d1, const AliMUONPad& d2,
222                            const TVector2& precision,
223                            AliMpArea& overlapRegion) 
224 {
225   /// Checks the overlap between 2 pads, and returns the overlap area
226   /// 
227   /// See comments on the other AreOverlapping method, too : in this
228   /// method, the overlapRegion does *not* depend on the precision parameter,
229   /// which is only used to decide whether the pads are overlapping, while
230   /// the actual overlap region is computed w/o reference to precision.
231   ///
232   if ( AreOverlapping(d1,d2,precision) )
233   {
234     overlapRegion = Overlap(d1,d2);
235     if ( !overlapRegion.IsValid() )
236     {
237       cerr << "Something is wrong : the 2 pads below are flagged as overlapping"
238       << ", but the overlapRegion is not valid"
239       << endl;
240       d1.Print("corners");
241       d2.Print("corners");
242     }
243     return kTRUE;
244   }
245   return kFALSE;
246 }
247
248 //_____________________________________________________________________________
249 Int_t 
250 AliMUONPad::Compare(const TObject* obj) const
251 {
252   /// Compare 2 pads. 
253   /// Ordering is as complete as possible.
254   
255   const AliMUONPad* pad = static_cast<const AliMUONPad*>(obj);
256     
257   if (DetElemId() < 0)
258   {
259     // AZ - For "pixels" from MLEM cluster finder
260     // we only sort on charge
261     if (Charge() == pad->Charge()) return 0;
262     return ( Charge() < pad->Charge() ) ? 1:-1;
263   }
264
265   if ( DetElemId() > pad->DetElemId() )
266   {
267     return 1;
268   }
269   else if ( DetElemId() < pad->DetElemId() )
270   {
271     return -1;
272   }
273   else
274   {
275     // same DetElemId...
276     if ( Cathode() > pad->Cathode() )
277     {
278       return 1;
279     }
280     else if ( Cathode() < pad->Cathode() ) 
281     {
282       return -1;
283     }
284     else
285     {
286       // same cathode...
287       if ( Ix() > pad->Ix() )
288       {
289         return 1;
290       }
291       else if ( Ix() < pad->Ix() ) 
292       {
293         return -1;
294       }
295       else
296       {
297         // same ix....
298         if ( Iy() > pad->Iy() )
299         {
300           return 1;
301         }
302         else if ( Iy() < pad->Iy() ) 
303         {
304           return -1;
305         }
306         else
307         {
308           // same iy....
309           if ( X() > pad->X() )
310           {
311             return 1;
312           }
313           else if ( X() < pad->X() )
314           {
315             return -1;
316           }
317           else
318           {
319             // same X
320             if ( Y() > pad->Y() )
321             {
322               return 1;
323             }
324             else if ( Y() < pad->Y() )
325             {
326               return -1;
327             }
328             else
329             {
330               // same Y
331               if ( Charge() < pad->Charge() ) 
332               {
333                 return -1;
334               }
335               else if ( Charge() > pad->Charge() )
336               {
337                 return 1;
338               }
339               else
340               {
341                 return 0;
342               }
343             }
344           }          
345         }        
346       }
347     }
348   }
349   return 0;
350 }
351
352 //_____________________________________________________________________________
353 Double_t
354 AliMUONPad::Coord(Int_t ixy) const
355 {
356   /// To be friendly and backward compatible with AZ code, which 
357   /// used that kind of coordinate accessing.
358   
359   if ( ixy == 0 ) 
360   {
361     return X();
362   }
363   else if ( ixy == 1 )
364   {
365     return Y();
366   }
367   AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
368   return 0;
369 }
370
371 //_____________________________________________________________________________
372 void 
373 AliMUONPad::Init(Int_t detElemId, Int_t cathode,
374                  Int_t ix, Int_t iy,
375                  const TVector2& position,
376                  const TVector2& dimensions,
377                  Double_t charge)
378 {
379   /// Called by all the ctors
380   fIsSaturated = kFALSE;
381   fIsReal = kTRUE;
382   fDetElemId = detElemId;
383   fCathode = cathode;
384   fIx = ix;
385   fIy = iy;
386   fPosition = position;
387   fDimensions = dimensions;
388   fCharge = charge;
389   fChargeBackup = fCharge;
390   
391   fClusterId = -1;
392
393   fStatus = 0;
394 }
395
396 //_____________________________________________________________________________
397 AliMpArea
398 AliMUONPad::Overlap(const AliMUONPad& d1, const AliMUONPad& d2)
399 {  
400   /// Return the overlap region between two pads
401   AliMpArea a1(d1.X(),d1.Y(),d1.DX(),d1.DY());
402   AliMpArea a2(d2.X(),d2.Y(),d2.DX(),d2.DY());
403   return Intersect(a1,a2);
404 }
405
406
407 //_____________________________________________________________________________
408 void
409 AliMUONPad::Paint(Option_t*)
410 {
411   /// Paint pad on screen
412   TVector2 ll = Position() - Dimensions();
413   TVector2 ur = Position() + Dimensions();
414
415   gPad->PaintBox(ll.X(),ll.Y(),ur.X(),ur.Y());
416 }
417
418 //_____________________________________________________________________________
419 void
420 AliMUONPad::Print(Option_t* opt) const
421 {
422   /// Printout
423   TString sopt(opt);
424   sopt.ToLower();
425   
426   ios_base::fmtflags oldflags = cout.flags();
427   if ( Cathode() >= 0 )
428   {
429     cout << "DetEle " << setw(5) << DetElemId()
430     << " Cath " << setw(2) << Cathode()
431     << " (Ix,Iy)=(" << setw(3) << Ix() << "," << setw(3) << Iy() << ") ";
432   }
433   cout.setf(ios::fixed);
434   cout.precision(6);
435   cout << " (x,y)=(" << setw(9) << X() << "," << setw(9) << Y() << ") "
436   << " (dx,dy)=(" << setw(9) << DX() << "," << setw(9) << DY() << ") "
437   << " Charge=";
438   cout.precision(2);
439   cout << setw(7) << Charge();
440   if ( sopt.Contains("full") )
441   {
442     cout 
443     << " Used=" << (IsUsed()?Form("YES (ClusterId %d)",fClusterId):"NO")
444     << (IsSaturated()?"(S)":"   ")
445     << (IsReal()?"   ":"(V)")
446     << " Status=" << setw(4) << Status()
447     << " ChargeBackup=" << ChargeBackup();
448   }
449   if ( sopt.Contains("corners") )
450   {
451     cout << Form(" (xmin,xmax)=(%e,%e) (ymin,ymax)=(%e,%e)",
452                  X()-DX(),X()+DX(),
453                  Y()-DY(),Y()+DY()) << endl;
454   }
455   cout << endl;
456   cout.precision(6); // reset to default precision
457   cout.flags(oldflags);
458 }
459
460 //_____________________________________________________________________________
461 void 
462 AliMUONPad::SetCoord(Int_t ixy, Double_t coord)
463 {
464   /// Set the pad coordinate (ixy=0 means x, ixy=1 means y)
465   if ( ixy == 0 ) 
466   {
467     fPosition.Set(coord,Y());
468   }
469   else if ( ixy == 1 )
470   {
471     fPosition.Set(X(),coord);
472   }
473   else
474   {
475     AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
476   }
477 }
478
479 //_____________________________________________________________________________
480 void 
481 AliMUONPad::SetSize(Int_t ixy, Double_t size)
482 {
483   /// Set the pad half size (ixy=0 means x half size, ixy=1 means y half size)
484   if ( ixy == 0 ) 
485   {
486     fDimensions.Set(size,DY());
487   }
488   else if ( ixy == 1 )
489   {
490     fDimensions.Set(DX(),size);
491   }
492   else
493   {
494     AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
495   }
496 }
497
498 //_____________________________________________________________________________
499 void 
500 AliMUONPad::Shift(Int_t ixy, Double_t shift)
501 {
502   /// Shift the position by "shift"
503   SetCoord(ixy,Coord(ixy)+shift);
504 }
505
506 //_____________________________________________________________________________
507 Double_t
508 AliMUONPad::Size(Int_t ixy) const
509 {
510   /// Returns the half size along a direction, given by ixy
511   /// (see SetSize for ixy meaning)
512   
513   if ( ixy == 0 ) 
514   {
515     return DX();
516   }
517   else if ( ixy == 1 )
518   {
519     return DY();
520   }
521   AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
522   return 0;
523 }