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