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