]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONCluster.cxx
In AliMUONCluster:
[u/mrichter/AliRoot.git] / MUON / AliMUONCluster.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 <Riostream.h>
19 #include <TMath.h>
20 #include <TObjArray.h>
21 #include <TVirtualPad.h>
22 #include <TVirtualX.h>
23
24 #include "AliMUONCluster.h"
25 #include "AliMUONPad.h"
26
27 #include "AliMpEncodePair.h"
28
29 #include "AliLog.h"
30
31 //-----------------------------------------------------------------------------
32 /// \class AliMUONCluster
33 ///
34 /// A group of adjacent pads
35 ///
36 /// Besides holding an internal array of AliMUONPads, this object
37 /// also computes some global characteristics for that pad sets.
38 ///
39 /// \author Laurent Aphecetche
40 ///
41 //-----------------------------------------------------------------------------
42
43 /// \cond CLASSIMP
44 ClassImp(AliMUONCluster)
45 /// \endcond
46
47 namespace
48 {
49   //___________________________________________________________________________
50   Bool_t
51   ShouldUsePad(const AliMUONPad& pad, 
52                Int_t cathode, Int_t statusMask, Bool_t matchMask)
53   {
54
55       // FIXME : we should only use >=0 status, so we can fully
56       // use masking possibility ?
57     if ( pad.Status() < 0 ) return kFALSE;
58     
59     if ( pad.Cathode() == cathode && pad.IsReal() && !pad.IsSaturated() )
60     {
61       Bool_t test = ( ( pad.Status() & statusMask ) != 0 );
62       if ( !statusMask ) 
63       {
64         test = ( pad.Status() == 0 );
65       }
66       if ( ( test && matchMask ) || ( !test && !matchMask ) )
67       {
68         return kTRUE;
69       }
70     }
71     return kFALSE;
72   }
73
74   //___________________________________________________________________________
75   Int_t Unique(Int_t n, Double_t* array, Double_t precision)
76   {
77     /// Return the number of *different* elements in array 
78     /// where different is up to precision
79     /// Note that we assume that n is >= 1
80     
81     Int_t count(1);
82     
83     Int_t* index = new Int_t[n];
84     
85     TMath::Sort(n,array,index);
86         
87     for ( Int_t i = 1; i < n; ++i )
88     {
89       if ( array[index[i]] - array[index[i-1]] < -precision ) ++count;
90     }
91     
92     delete[] index;
93         
94     return count;
95   }
96 }
97
98 //_____________________________________________________________________________
99 AliMUONCluster::AliMUONCluster() 
100 : TObject(), 
101 fPads(),
102 fHasPosition(kFALSE),
103 fPosition(1E9,1E9),
104 fPositionError(1E9,1E9),
105 fHasCharge(kFALSE),
106 fChi2(0)
107 {
108   /// ctor
109   fMultiplicity[0]=fMultiplicity[1]=0;
110   fRawCharge[0]=fRawCharge[1]=0;
111   fCharge[0]=fCharge[1]=0;
112   fIsSaturated[0]=fIsSaturated[1]=kFALSE;
113   fPads.SetOwner(kTRUE);
114 }
115
116 //_____________________________________________________________________________
117 AliMUONCluster::AliMUONCluster(const AliMUONCluster& src)
118 : TObject(src),
119 fPads(),
120 fHasPosition(kFALSE),
121 fPosition(1E9,1E9),
122 fPositionError(1E9,1E9),
123 fHasCharge(kFALSE),
124 fChi2(0)
125 {
126   /// copy ctor
127   fPads.SetOwner(kTRUE);
128   src.Copy(*this);
129 }
130
131 //_____________________________________________________________________________
132 AliMUONCluster&
133 AliMUONCluster::operator=(const AliMUONCluster& src)
134 {
135   /// assignement operator
136   if ( this != &src ) 
137   {
138     src.Copy(*this);
139   }
140   return *this;
141 }
142
143 //_____________________________________________________________________________
144 AliMUONCluster::~AliMUONCluster()
145 {
146   /// dtor : note that we're owner of our pads
147   //  fPads.Delete();
148 }
149
150 //_____________________________________________________________________________
151 void
152 AliMUONCluster::Clear(Option_t*)
153 {
154   /// Clear our pad array.
155   /// We have to call the destructor of TObjArray to be sure that all
156   /// allocated memory is released.
157   fPads.~TObjArray();
158 }
159
160 //_____________________________________________________________________________
161 Bool_t
162 AliMUONCluster::Contains(const AliMUONPad& pad) const
163 {
164   /// Whether this cluster contains the pad
165   if (fPads.IsEmpty()) return kFALSE;
166   
167   for ( Int_t i = 0; i < Multiplicity(); ++i ) 
168   {
169     AliMUONPad* p = Pad(i);
170     if ( pad.Compare(p) == 0 ) return kTRUE;
171   }
172   return kFALSE;
173 }
174
175 //_____________________________________________________________________________
176 void
177 AliMUONCluster::AddCluster(const AliMUONCluster& cluster)
178 {
179   /// Add all the pads for cluster to this one
180   for ( Int_t i = 0; i < cluster.Multiplicity(); ++i )
181   {
182     AliMUONPad* p = cluster.Pad(i);
183     if ( Contains(*p) ) 
184     {
185       AliError("I already got this pad : ");
186       StdoutToAliError(p->Print(););
187       AliFatal("");
188     }
189     AddPad(*p);
190   }
191   
192 }
193
194 //_____________________________________________________________________________
195 AliMUONPad*
196 AliMUONCluster::AddPad(const AliMUONPad& pad)
197 {
198   /// Add a pad to our pad array, and update some internal information
199   /// accordingly.
200
201   AliMUONPad* p = new AliMUONPad(pad);
202   fPads.AddLast(p);
203   p->SetClusterId(GetUniqueID());
204   Int_t cathode = p->Cathode();
205   ++(fMultiplicity[cathode]);
206   fRawCharge[cathode] += p->Charge();
207   if ( p->IsSaturated() )
208   {
209     fIsSaturated[p->Cathode()]=kTRUE;
210   }
211   return p;
212 }
213
214 //___________________________________________________________________________
215 TString
216 AliMUONCluster::AsString() const
217 {
218   /// Return a string containing a compact form of the pad list
219   TString s(Form("NPADS(%d,%d)",Multiplicity(0),Multiplicity(1)));
220   
221   for (Int_t i = 0; i < Multiplicity(); ++i ) 
222   {
223     AliMUONPad* p = Pad(i);
224     s += Form(" (%d,%d,%d) ",p->Cathode(),p->Ix(),p->Iy());
225   }
226   return s;
227 }
228
229
230 //___________________________________________________________________________
231 Bool_t
232 AliMUONCluster::AreOverlapping(const AliMUONCluster& c1, const AliMUONCluster& c2)
233 {
234   /// Whether the two clusters overlap
235   
236   static Double_t precision = 1E-4; // cm
237   static TVector2 precisionAdjustment(precision,precision);
238     
239   for ( Int_t i1 = 0; i1 < c1.Multiplicity(); ++i1 )
240   {
241     AliMUONPad* p1 = c1.Pad(i1);
242     
243     for ( Int_t i2 = 0; i2 < c2.Multiplicity(); ++i2 )
244     {
245       AliMUONPad* p2 = c2.Pad(i2);
246       // Note: we use negative precision numbers, meaning
247       // the area of the pads will be *increased* by these small numbers
248       // prior to check the overlap by the AreOverlapping method,
249       // so pads touching only by the corners will be considered as
250       // overlapping.    
251       if ( AliMUONPad::AreOverlapping(*p1,*p2,precisionAdjustment) )
252       {
253         return kTRUE;
254       }
255     }
256   }
257   return kFALSE;
258 }
259
260 //_____________________________________________________________________________
261 AliMpArea
262 AliMUONCluster::Area() const
263 {
264   /// Return the geometrical area covered by this cluster
265   
266   // Start by finding the (x,y) limits of this cluster
267   TVector2 lowerLeft(1E9,1E9);
268   TVector2 upperRight(-1E9,-1E9);
269   
270   for ( Int_t i = 0; i < Multiplicity(); ++i )
271   {
272     AliMUONPad* pad = Pad(i);
273     TVector2 ll = pad->Position() - pad->Dimensions();
274     TVector2 ur = pad->Position() + pad->Dimensions();
275     lowerLeft.Set( TMath::Min(ll.X(),lowerLeft.X()),
276                    TMath::Min(ll.Y(),lowerLeft.Y()) );
277     upperRight.Set( TMath::Max(ur.X(),upperRight.X()),
278                     TMath::Max(ur.Y(),upperRight.Y()) );
279   }
280
281   // then construct the area from those limits
282   return AliMpArea((lowerLeft+upperRight).X()/2,(lowerLeft+upperRight).Y()/2, 
283                    (upperRight-lowerLeft).X()/2, (upperRight-lowerLeft).Y()/2);
284 }
285
286 //_____________________________________________________________________________
287 AliMpArea
288 AliMUONCluster::Area(Int_t cathode) const
289 {
290   /// Return the geometrical area covered by this cluster's pads on 
291   /// a given cathode
292   
293   // Start by finding the (x,y) limits of this cluster
294   TVector2 lowerLeft(1E9,1E9);
295   TVector2 upperRight(-1E9,-1E9);
296   
297   for ( Int_t i = 0; i < Multiplicity(); ++i )
298   {
299     AliMUONPad* pad = Pad(i);
300     if ( pad->Cathode() == cathode ) 
301     {
302       TVector2 ll = pad->Position() - pad->Dimensions();
303       TVector2 ur = pad->Position() + pad->Dimensions();
304       lowerLeft.Set( TMath::Min(ll.X(),lowerLeft.X()),
305                      TMath::Min(ll.Y(),lowerLeft.Y()) );
306       upperRight.Set( TMath::Max(ur.X(),upperRight.X()),
307                       TMath::Max(ur.Y(),upperRight.Y()) );
308     }
309   }
310   
311   // then construct the area from those limits
312   return AliMpArea((lowerLeft+upperRight).X()/2,(lowerLeft+upperRight).Y()/2,
313                    (upperRight-lowerLeft).X()/2, (upperRight-lowerLeft).Y()/2);
314 }
315
316 //_____________________________________________________________________________
317 Bool_t
318 AliMUONCluster::IsMonoCathode() const
319 {
320   /// Whether we have signals only in one of the two cathodes
321   return (Cathode()<2);
322 }
323
324 //_____________________________________________________________________________
325 Int_t
326 AliMUONCluster::Cathode() const
327 {
328   /// Return the cathode "number" of this cluster : 
329   /// 0 if all its pads are on cathode 0
330   /// 1 if all its pads are on cathode 1
331   /// 2 if some pads on cath 0 and some on cath 1
332   
333   Int_t cathode(-1);
334   if (Multiplicity(0)>0 && Multiplicity(1)>0) 
335   {
336     cathode=2;
337   }
338   else if (Multiplicity(0)>0) 
339   {
340     cathode=0;
341   }
342   else if (Multiplicity(1)>0) 
343   {
344     cathode=1;
345   }
346   
347   return cathode;
348 }
349
350 //_____________________________________________________________________________
351 void
352 AliMUONCluster::Copy(TObject& obj) const
353 {
354   ///
355   /// Copy this cluster to (cluster&)obj
356   ///
357   TObject::Copy(obj);
358   AliMUONCluster& dest = static_cast<AliMUONCluster&>(obj);
359
360 //  dest.fPads.Delete();
361   dest.fPads.Clear();
362   
363   for ( Int_t i = 0; i <= fPads.GetLast(); ++i ) 
364   {
365     AliMUONPad* p = static_cast<AliMUONPad*>(fPads.UncheckedAt(i));
366     dest.fPads.AddLast(new AliMUONPad(*p));
367   }
368   dest.fHasPosition = fHasPosition;
369   dest.fPosition = fPosition;
370   dest.fPositionError = fPositionError;
371   dest.fHasCharge = fHasCharge;
372   dest.fChi2 = fChi2;
373   for ( Int_t i = 0; i < 2; ++i )
374   {
375     dest.fRawCharge[i] = fRawCharge[i];
376     dest.fCharge[i] = fCharge[i];
377     dest.fMultiplicity[i] = fMultiplicity[i];
378     dest.fIsSaturated[i] = fIsSaturated[i];
379   }
380 }
381
382 //_____________________________________________________________________________
383 Float_t 
384 AliMUONCluster::Charge() const
385 {
386   /// Return the average charge over both cathodes
387   
388   if ( Multiplicity(0) && Multiplicity(1) )
389   {
390     return (Charge(0)+Charge(1))/2.0;
391   }
392   else if ( Multiplicity(0) ) 
393   {
394     return Charge(0);
395   }
396   else if ( Multiplicity(1) ) 
397   {
398     return Charge(1);
399   }
400   AliError("Should not be here ?!");
401   return -1.0;
402 }
403
404 //_____________________________________________________________________________
405 Float_t
406 AliMUONCluster::Charge(Int_t cathode) const
407 {
408   /// Returns the charge of a given cathode
409   if ( !fHasCharge ) return RawCharge(cathode);
410   
411   if ( cathode == 0 || cathode == 1 )
412   {
413     return fCharge[cathode];
414   }
415   return 0;
416 }
417
418 //_____________________________________________________________________________
419 Float_t
420 AliMUONCluster::ChargeAsymmetry() const
421 {
422   /// Returns the charge asymmetry
423   if ( Charge() > 0 )
424   {
425     return TMath::Abs(Charge(0)-Charge(1))/Charge();
426   }
427   return 0;
428 }
429
430 //_____________________________________________________________________________
431 TVector2
432 AliMUONCluster::MaxPadDimensions(Int_t statusMask, Bool_t matchMask) const
433 {
434   /// Returns the maximum pad dimensions (half sizes), only considering
435   /// pads matching (or not, depending matchMask) a given mask
436   
437   TVector2 cath0(MaxPadDimensions(0,statusMask,matchMask)); 
438   TVector2 cath1(MaxPadDimensions(1,statusMask,matchMask)); 
439   
440   return TVector2( TMath::Max(cath0.X(),cath1.X()),
441                    TMath::Max(cath0.Y(),cath1.Y()) );
442 }
443
444 //_____________________________________________________________________________
445 TVector2
446 AliMUONCluster::MaxPadDimensions(Int_t cathode, 
447                                  Int_t statusMask, Bool_t matchMask) const
448 {
449   /// Returns the maximum pad dimensions (half sizes), only considering
450   /// pads matching (or not, depending matchMask) a given mask, within a
451   /// given cathode
452   
453   Double_t xmax(0);
454   Double_t ymax(0);
455   
456   for ( Int_t i = 0; i < Multiplicity(); ++i )
457   {
458     AliMUONPad* pad = Pad(i);
459     if ( ShouldUsePad(*pad,cathode,statusMask,matchMask) )
460     {
461       xmax = TMath::Max(xmax,pad->DX());
462       ymax = TMath::Max(ymax,pad->DY());
463     }
464   }
465   return TVector2(xmax,ymax);
466 }
467
468 //_____________________________________________________________________________
469 TVector2
470 AliMUONCluster::MinPadDimensions(Int_t statusMask, Bool_t matchMask) const
471 {
472   /// Returns the minimum pad dimensions (half sizes), only considering
473   /// pads matching (or not, depending matchMask) a given mask
474   
475   TVector2 cath0(MinPadDimensions(0,statusMask,matchMask)); 
476   TVector2 cath1(MinPadDimensions(1,statusMask,matchMask)); 
477   
478   return TVector2( TMath::Min(cath0.X(),cath1.X()),
479                    TMath::Min(cath0.Y(),cath1.Y()) );
480 }
481
482 //_____________________________________________________________________________
483 TVector2
484 AliMUONCluster::MinPadDimensions(Int_t cathode, 
485                                  Int_t statusMask, Bool_t matchMask) const
486 {
487   /// Returns the minimum pad dimensions (half sizes), only considering
488   /// pads matching (or not, depending matchMask) a given mask, within a
489   /// given cathode
490   
491   Double_t xmin(1E9);
492   Double_t ymin(1E9);
493     
494   for ( Int_t i = 0; i < Multiplicity(); ++i )
495   {
496     AliMUONPad* pad = Pad(i);
497     if ( ShouldUsePad(*pad,cathode,statusMask,matchMask) )
498     {
499       xmin = TMath::Min(xmin,pad->DX());
500       ymin = TMath::Min(ymin,pad->DY());
501     }
502   }
503   return TVector2(xmin,ymin);
504 }
505
506 //_____________________________________________________________________________
507 Int_t 
508 AliMUONCluster::Multiplicity() const
509 {
510   /// Returns the total number of pads in this cluster
511   return Multiplicity(0)+Multiplicity(1);
512 }
513
514 //_____________________________________________________________________________
515 Int_t
516 AliMUONCluster::Multiplicity(Int_t cathode) const
517 {
518   /// Returns the number of pads in this cluster, in the given cathode
519   if ( cathode == 0 || cathode == 1 )
520   {
521     return fMultiplicity[cathode];
522   }
523   return 0;
524 }
525
526 //_____________________________________________________________________________
527 Long_t
528 AliMUONCluster::NofPads(Int_t statusMask, Bool_t matchMask) const
529 {
530   /// Number of pads satisfying (or not, depending matchMask) a
531   /// given mask 
532   
533   Int_t nx, ny;
534   
535   TVector2 dim0(MinPadDimensions(0,statusMask,matchMask));
536   TVector2 dim1(MinPadDimensions(1,statusMask,matchMask));
537   
538   Long_t npad0(NofPads(0,statusMask,matchMask));
539   Long_t npad1(NofPads(1,statusMask,matchMask));
540   
541   if ( TMath::Abs( (dim0-dim1).X() ) < 1E-3 )
542   {
543     nx = TMath::Max( AliMp::PairFirst(npad0), AliMp::PairFirst(npad1) );
544   }
545   else
546   {
547     nx = dim0.X() < dim1.X() ? AliMp::PairFirst(npad0) : AliMp::PairFirst(npad1);
548   }
549   
550   if ( TMath::Abs( (dim0-dim1).Y() ) < 1E-3 )
551   {
552     ny = TMath::Max( AliMp::PairSecond(npad0), AliMp::PairSecond(npad1) );
553   }
554   else
555   {
556     ny = dim0.Y() < dim1.Y() ? AliMp::PairSecond(npad0) : AliMp::PairSecond(npad1);
557   }
558   
559   return AliMp::Pair(nx,ny);
560 }
561
562 //_____________________________________________________________________________
563 Long_t
564 AliMUONCluster::NofPads(Int_t cathode,
565                         Int_t statusMask, Bool_t matchMask) const
566 {
567   /// Number of pads of a given cathode, satisfying (or not, 
568   /// depending matchMask) a given mask
569
570   Int_t n = Multiplicity(cathode);
571   if (!n) 
572   {
573     return 0;
574   }
575   Double_t* x = new Double_t[n];
576   Double_t* y = new Double_t[n];
577   Int_t np(0);
578   
579   for ( Int_t i = 0; i < Multiplicity(); ++i )
580   {
581     AliMUONPad* pad = Pad(i);
582     if ( ShouldUsePad(*pad,cathode,statusMask,matchMask) )
583     {
584       x[np] = pad->X();
585       y[np] = pad->Y();
586       ++np;
587     }
588   }
589   
590   Int_t cx = Unique(np,x,0.01);
591   Int_t cy = Unique(np,y,0.01);
592   
593   delete[] x;
594   delete[] y;
595   
596   return AliMp::Pair(cx,cy);
597 }
598
599 //_____________________________________________________________________________
600 AliMUONPad*
601 AliMUONCluster::Pad(Int_t index) const
602 {
603   /// Returns the index-th pad
604   
605   if (fPads.IsEmpty()) return 0x0;
606   if ( index < fPads.GetLast()+1 )
607   {
608     return static_cast<AliMUONPad*>(fPads.At(index));
609   }
610   else
611   {
612     AliError(Form("Requested index %d out of bounds (%d) Mult is %d",index,
613                   fPads.GetLast(),Multiplicity()));
614     DumpMe();
615   }
616   return 0x0;
617 }
618
619
620 //_____________________________________________________________________________
621 void
622 AliMUONCluster::Paint(Option_t*)
623 {
624   /// Paint this cluster   
625   if (!Multiplicity()) return;
626   
627   AliMpArea area(Area());
628   
629   gPad->Range(area.LeftBorder(),area.DownBorder(),area.RightBorder(),area.UpBorder());
630       
631   gVirtualX->SetFillStyle(0);
632   
633   gVirtualX->SetLineColor(2);
634   gVirtualX->SetLineWidth(4);  
635   for ( Int_t i = 0; i < Multiplicity(); ++i)
636   {
637     AliMUONPad* pad = Pad(i);
638     if ( pad->Cathode() == 0 ) pad->Paint();
639   }
640
641   gVirtualX->SetLineColor(4);
642   gVirtualX->SetLineWidth(2);  
643   for ( Int_t i = 0; i < Multiplicity(); ++i)
644   {
645     AliMUONPad* pad = Pad(i);
646     if ( pad->Cathode() == 1 ) pad->Paint();
647   }
648   
649 }
650
651 //_____________________________________________________________________________
652 void
653 AliMUONCluster::DumpMe() const
654 {
655   /// printout
656   cout << "Cluster Id " << GetUniqueID() << " npads=" << Multiplicity() 
657   << "(" << Multiplicity(0) << "," << Multiplicity(1) << ") RawCharge=" 
658   << RawCharge() << " (" << RawCharge(0) << "," << RawCharge(1)
659   << ") Charge=(" << Charge(0) << "," << Charge(1) <<")";
660   if ( HasPosition() )
661   {
662     cout << " (x,y)=(" << Position().X() << "," << Position().Y() << ")";
663     cout << " (errX,errY)=(" << PositionError().X() << "," << PositionError().Y() << ")";
664   }
665   cout << endl;
666 //  cout << " " << Area() << endl;
667   for (Int_t i = 0; i < fPads.GetSize(); ++i) 
668   {
669     cout << Form("fPads[%d]=%p",i,fPads.At(i)) << endl;
670     if ( fPads.At(i) ) fPads.At(i)->Print();
671   }
672 }
673
674
675 //_____________________________________________________________________________
676 void
677 AliMUONCluster::Print(Option_t* opt) const
678 {
679   /// printout
680   cout << "Cluster Id " << GetUniqueID() << " npads=" << Multiplicity() 
681   << "(" << Multiplicity(0) << "," << Multiplicity(1) << ") RawCharge=" 
682   << RawCharge() << " (" << RawCharge(0) << "," << RawCharge(1)
683   << ") Charge=(" << Charge(0) << "," << Charge(1) <<")";
684   if ( HasPosition() )
685   {
686     cout << " (x,y)=(" << Position().X() << "," << Position().Y() << ")";
687     cout << " (errX,errY)=(" << PositionError().X() << "," << PositionError().Y() << ")";
688   }
689   cout << " " << Area();
690
691   TObjArray* a = static_cast<TObjArray*>(fPads.Clone());
692   a->Sort();
693   a->Print("",opt);
694   delete a;
695 }
696
697 //_____________________________________________________________________________
698 //Bool_t
699 //AliMUONCluster::IsEqual(const TObject* obj) const
700 //{
701 //  const AliMUONCluster* c = static_cast<const AliMUONCluster*>(obj);
702 //  if ( c->Multiplicity() != Multiplicity() ) return kFALSE;
703 //  
704 //  for ( Int_t i = 0; i < c->Multiplicity(); ++i ) 
705 //  {
706 //    AliMUONPad* p = c->Pad(i);
707 //    if ( p->Compare(Pad(i)) ) return kFALSE;
708 //  }
709 //  return kTRUE;
710 //}
711
712 //_____________________________________________________________________________
713 Int_t 
714 AliMUONCluster::Compare(const TObject* obj) const
715 {
716   /// Compare two clusters. Comparison is made on position and rawcharge only.
717   
718   const AliMUONCluster* cluster = static_cast<const AliMUONCluster*>(obj);
719   
720   AliMpArea carea(cluster->Area());
721   AliMpArea area(Area());
722
723   if ( carea.GetPositionX() > area.GetPositionX() ) 
724   {
725     return 1;
726   }
727   else if ( carea.GetPositionX() < area.GetPositionX() ) 
728   {
729     return -1;
730   }
731   else 
732   {
733     if ( carea.GetPositionY() > area.GetPositionY() ) 
734     {
735       return 1;
736     }
737     else if ( carea.GetPositionY() < area.GetPositionY() ) 
738     {
739       return -1;
740     }
741     else
742     {
743       if ( cluster->RawCharge() > RawCharge() ) 
744       {
745         return 1;
746       }
747       else if ( cluster->RawCharge() < RawCharge() )
748       {
749         return -1;
750       }
751     }
752   }
753   return 0;
754 }
755
756 //_____________________________________________________________________________
757 void
758 AliMUONCluster::RemovePad(AliMUONPad* pad)
759 {
760   /// Remove a pad. 
761   /// As a consequence, some internal information must be updated
762   
763   fPads.Remove(pad);
764   fPads.Compress();
765   delete pad;
766   // update cluster's data
767   fIsSaturated[0]=fIsSaturated[1]=kFALSE;
768   fMultiplicity[0]=fMultiplicity[1]=0;
769   fRawCharge[0]=fRawCharge[1]=0;
770   for ( Int_t i = 0; i <= fPads.GetLast(); ++i )
771   {
772     AliMUONPad* p = Pad(i);
773     if ( p->IsSaturated() ) 
774     {
775       fIsSaturated[p->Cathode()] = kTRUE;
776     }
777     ++fMultiplicity[p->Cathode()];
778     fRawCharge[p->Cathode()] += p->Charge();
779   }
780 }
781
782 //_____________________________________________________________________________
783 Float_t 
784 AliMUONCluster::RawCharge() const
785 {
786   /// Returns the raw average charge
787   return (RawCharge(0)+RawCharge(1))/2.0;
788 }
789
790 //_____________________________________________________________________________
791 Float_t
792 AliMUONCluster::RawCharge(Int_t cathode) const
793 {
794   /// Returns the average charge of a given cathode
795   if ( cathode == 0 || cathode == 1 )
796   {
797     return fRawCharge[cathode];
798   }
799   return 0;
800 }
801
802 //_____________________________________________________________________________
803 Float_t
804 AliMUONCluster::RawChargeAsymmetry() const
805 {
806   /// Returns the raw charge asymmetry
807    if ( RawCharge() > 0 )
808    {
809      return TMath::Abs(RawCharge(0)-RawCharge(1))/RawCharge();
810    }
811   return 0;
812 }