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