7be9d5630695ac46aae2920be456c97c60b32f37
[u/mrichter/AliRoot.git] / MUON / AliMUONPreClusterFinder.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 "AliMUONPreClusterFinder.h"
19
20 #include "AliLog.h"
21 #include "AliMUONCluster.h"
22 #include "AliMpVSegmentation.h"
23 #include "TClonesArray.h"
24 #include "AliMpArea.h"
25 #include "TVector2.h"
26 #include "AliMUONPad.h"
27 #include "AliMUONVDigit.h"
28 #include "AliMUONVDigitStore.h"
29 //#include "AliCodeTimer.h"
30
31 //-----------------------------------------------------------------------------
32 /// \class AliMUONPreClusterFinder
33 ///
34 /// Implementation of AliMUONVClusterFinder
35 ///
36 /// This class simply find adjacent pads to form clusters
37 ///
38 /// \author Laurent Aphecetche
39 //-----------------------------------------------------------------------------
40
41 ClassImp(AliMUONPreClusterFinder)
42
43 //_____________________________________________________________________________
44 AliMUONPreClusterFinder::AliMUONPreClusterFinder()
45 : AliMUONVClusterFinder(),
46   fClusters(0x0),
47   fSegmentations(0x0),
48   fDetElemId(0)
49 {
50     /// ctor
51   for ( Int_t i = 0; i < 2; ++i )
52   {
53     fPads[i] = 0x0;
54   } 
55 }
56
57 //_____________________________________________________________________________
58 AliMUONPreClusterFinder::~AliMUONPreClusterFinder()
59 {
60   /// dtor : note we're owner of the pads and the clusters, but not of
61   /// the remaining objects (digits, segmentations)
62   delete fClusters;
63   for ( Int_t i = 0; i < 2; ++i )
64   {
65     delete fPads[i];
66   }  
67 }
68
69 //_____________________________________________________________________________
70 Bool_t
71 AliMUONPreClusterFinder::UsePad(const AliMUONPad& pad)
72 {
73   /// Add a pad to the list of pads to be considered
74   if ( pad.DetElemId() != fDetElemId )
75   {
76     AliError(Form("Cannot add pad from DE %d to this cluster finder which is "
77                   "currently dealing with DE %d",pad.DetElemId(),fDetElemId));
78     return kFALSE;
79   }
80   
81   new ((*fPads[pad.Cathode()])[fPads[pad.Cathode()]->GetLast()+1]) AliMUONPad(pad); 
82   // FIXME: should set the ClusterId of that new pad to be -1
83   return kTRUE;
84 }
85
86 //_____________________________________________________________________________
87 Bool_t
88 AliMUONPreClusterFinder::Prepare(const AliMpVSegmentation* segmentations[2],
89                                  const AliMUONVDigitStore& digitStore)
90 // FIXME : add area on which to look for clusters here.
91 {
92   /// Prepare for clustering, by giving access to segmentations and digit lists
93   
94   fSegmentations = segmentations;
95   
96   delete fClusters;
97   fClusters = new TClonesArray("AliMUONCluster");
98   for ( Int_t i = 0; i < 2; ++i )
99   {
100     delete fPads[i];
101     fPads[i] = new TClonesArray("AliMUONPad");
102   }
103   
104   fDetElemId = -1;
105   
106   TIter next(digitStore.CreateIterator());
107   AliMUONVDigit* d;
108   
109   while ( ( d = static_cast<AliMUONVDigit*>(next()) ) )
110   {
111     Int_t ix = d->PadX();
112     Int_t iy = d->PadY();
113     Int_t cathode = d->Cathode();
114     AliMpPad pad = fSegmentations[cathode]->PadByIndices(AliMpIntPair(ix,iy));
115     TClonesArray& padArray = *(fPads[cathode]);
116     if ( fDetElemId == -1 ) 
117     {
118       fDetElemId = d->DetElemId();
119     }
120     else
121     {
122       if ( d->DetElemId() != fDetElemId ) 
123       {
124         AliError("Something is seriously wrong with DE. Aborting clustering");
125         return kFALSE;
126       }
127     }
128     
129     AliMUONPad mpad(fDetElemId,cathode,
130                     ix,iy,pad.Position().X(),pad.Position().Y(),
131                     pad.Dimensions().X(),pad.Dimensions().Y(),
132                     d->Charge());
133     if ( d->IsSaturated() ) mpad.SetSaturated(kTRUE);
134     mpad.SetUniqueID(d->GetUniqueID());
135     new (padArray[padArray.GetLast()+1]) AliMUONPad(mpad);      
136   }
137   if ( fPads[0]->GetLast() < 0 && fPads[1]->GetLast() < 0 )
138   {
139     // no pad at all, nothing to do...
140     return kFALSE;
141   }
142   
143   return kTRUE;
144 }
145
146 //_____________________________________________________________________________
147 void
148 AliMUONPreClusterFinder::AddPad(AliMUONCluster& cluster, AliMUONPad* pad)
149 {
150   /// Add a pad to a cluster
151   cluster.AddPad(*pad);
152   
153   Int_t cathode = pad->Cathode();
154   TClonesArray& padArray = *fPads[cathode];
155   // WARNING: this Remove method uses the AliMUONPad::IsEqual if that method is
156   // present (otherwise just compares pointers) : so that one must be correct
157   // if implemented !
158   padArray.Remove(pad);
159  // TObject* o = padArray.Remove(pad); 
160 //  if (!o)
161 //  {
162 //    AliFatal("Oups. Could not remove pad from pads to consider. Aborting as anyway "
163 //             " we'll get an infinite loop. Please check the AliMUONPad::IsEqual method"
164 //             " as the first suspect for failed remove");
165 //  }  
166   TIter next(&padArray);
167   AliMUONPad* testPad;
168
169   while ( ( testPad = static_cast<AliMUONPad*>(next())))
170   {
171     if ( AliMUONPad::AreNeighbours(*testPad,*pad) )
172     {
173       AddPad(cluster,testPad);
174     }
175   }
176 }
177
178 //_____________________________________________________________________________
179 Bool_t
180 AreOverlapping(const AliMUONPad& pad, const AliMUONCluster& cluster)
181 {
182   /// Whether the pad overlaps with the cluster
183   
184   static Double_t precision = 1E-4; // cm
185   static TVector2 precisionAdjustment(precision,precision);//-precision,-precision);
186   for ( Int_t i = 0; i < cluster.Multiplicity(); ++i )
187   {
188     AliMUONPad* testPad = cluster.Pad(i);
189     // Note: we use negative precision numbers, meaning
190     // the area of the pads will be *increased* by these small numbers
191     // prior to check the overlap by the AreOverlapping method,
192     // so pads touching only by the corners will be considered as
193     // overlapping.    
194     if ( AliMUONPad::AreOverlapping(*testPad,pad,precisionAdjustment) )
195     {
196       return kTRUE;
197     }
198   }
199   return kFALSE;
200 }
201
202 //_____________________________________________________________________________
203 AliMUONCluster* 
204 AliMUONPreClusterFinder::NextCluster()
205 {
206   /// Builds the next cluster, and returns it.
207 //  AliCodeTimerAuto("pre-clustering")
208   
209   // Start a new cluster
210   Int_t id = fClusters->GetLast()+1;
211   AliMUONCluster* cluster = new ((*fClusters)[id]) AliMUONCluster;
212   cluster->SetUniqueID(id);
213   
214   TIter next(fPads[0]);
215   AliMUONPad* pad = static_cast<AliMUONPad*>(next());
216   
217   if (!pad) // protection against no pad in first cathode, which might happen
218   {
219     // try other cathode
220     TIter next(fPads[1]);
221     pad = static_cast<AliMUONPad*>(next());
222     if (!pad) 
223     {
224       // we are done.
225       return 0x0;
226     }
227     // Builds (recursively) a cluster on second cathode only
228     AddPad(*cluster,pad);
229   }
230   else
231   {
232     // Builds (recursively) a cluster on first cathode only
233     AddPad(*cluster,pad);
234     
235     // On the 2nd cathode, only add pads overlapping with the current cluster
236     TClonesArray& padArray = *fPads[1];
237     TIter next(&padArray);
238     AliMUONPad* testPad;
239   
240     while ( ( testPad = static_cast<AliMUONPad*>(next())))
241     {
242       if ( AreOverlapping(*testPad,*cluster) )
243       {
244         AddPad(*cluster,testPad);
245       }
246     }
247   }
248   
249   if ( cluster->Multiplicity() <= 1 )
250   {
251     if ( cluster->Multiplicity() == 0 ) 
252     {
253       // no pad is suspicious
254       AliWarning("Got an empty cluster...");
255     }
256     // else only 1 pad (not suspicious, but kind of useless, probably noise)
257     // so we remove it from our list
258     fClusters->Remove(cluster);
259     fClusters->Compress();
260     // then proceed further
261     return NextCluster();
262   }
263   
264   return cluster;
265 }