]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONClusterFinderMLEM.cxx
Updated list of framework libraries
[u/mrichter/AliRoot.git] / MUON / AliMUONClusterFinderMLEM.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 //-----------------------------------------------------------------------------
19 /// \class AliMUONClusterFinderMLEM
20 /// 
21 /// Clusterizer class based on the Expectation-Maximization algorithm
22 ///
23 /// Pre-clustering is handled by AliMUONPreClusterFinder
24 /// From a precluster a pixel array is built, and from this pixel array
25 /// a list of clusters is output (using AliMUONClusterSplitterMLEM).
26 ///
27 /// \author Laurent Aphecetche (for the "new" C++ structure) and 
28 /// Alexander Zinchenko, JINR Dubna, for the hardcore of it ;-)
29 //-----------------------------------------------------------------------------
30
31 #include "AliMUONClusterFinderMLEM.h"
32 #include "AliLog.h"
33 #include "AliMUONCluster.h"
34 #include "AliMUONClusterSplitterMLEM.h"
35 #include "AliMUONVDigit.h"
36 #include "AliMUONPad.h"
37 #include "AliMUONPreClusterFinder.h"
38 #include "AliMpPad.h"
39 #include "AliMpVPadIterator.h"
40 #include "AliMpVSegmentation.h"
41 #include "AliRunLoader.h"
42 #include "AliMUONVDigitStore.h"
43 #include <Riostream.h>
44 #include <TH2.h>
45 #include <TMinuit.h>
46 #include <TCanvas.h>
47 #include <TMath.h>
48 #include <TROOT.h>
49 #include "AliCodeTimer.h"
50
51 /// \cond CLASSIMP
52 ClassImp(AliMUONClusterFinderMLEM)
53 /// \endcond
54  
55 const Double_t AliMUONClusterFinderMLEM::fgkZeroSuppression = 6; // average zero suppression value
56 //const Double_t AliMUONClusterFinderMLEM::fgkDistancePrecision = 1e-6; // (cm) used to check overlaps and so on
57 const Double_t AliMUONClusterFinderMLEM::fgkDistancePrecision = 1e-3; // (cm) used to check overlaps and so on
58 const TVector2 AliMUONClusterFinderMLEM::fgkIncreaseSize(-AliMUONClusterFinderMLEM::fgkDistancePrecision,-AliMUONClusterFinderMLEM::fgkDistancePrecision);
59 const TVector2 AliMUONClusterFinderMLEM::fgkDecreaseSize(AliMUONClusterFinderMLEM::fgkDistancePrecision,AliMUONClusterFinderMLEM::fgkDistancePrecision);
60
61  TMinuit* AliMUONClusterFinderMLEM::fgMinuit = 0x0;
62 // Status flags for pads
63 const Int_t AliMUONClusterFinderMLEM::fgkZero = 0x0; ///< pad "basic" state
64 const Int_t AliMUONClusterFinderMLEM::fgkMustKeep = 0x1; ///< do not kill (for pixels)
65 const Int_t AliMUONClusterFinderMLEM::fgkUseForFit = 0x10; ///< should be used for fit
66 const Int_t AliMUONClusterFinderMLEM::fgkOver = 0x100; ///< processing is over
67 const Int_t AliMUONClusterFinderMLEM::fgkModified = 0x1000; ///< modified pad charge 
68 const Int_t AliMUONClusterFinderMLEM::fgkCoupled = 0x10000; ///< coupled pad  
69
70 //_____________________________________________________________________________
71 AliMUONClusterFinderMLEM::AliMUONClusterFinderMLEM(Bool_t plot, AliMUONVClusterFinder* clusterFinder)
72   : AliMUONVClusterFinder(),
73 fPreClusterFinder(clusterFinder),
74 fPreCluster(0x0),
75 fClusterList(),
76 fEventNumber(0),
77 fDetElemId(-1),
78 fClusterNumber(0),
79 fCathBeg(0),
80 fPixArray(new TObjArray(20)),
81 fDebug(0),
82 fPlot(plot),
83 fSplitter(0x0),
84 fNClusters(0),
85 fNAddVirtualPads(0)
86 {
87   /// Constructor
88  
89   fSegmentation[1] = fSegmentation[0] = 0x0; 
90
91   fPadBeg[0] = fPadBeg[1] = fCathBeg;
92
93   if (!fgMinuit) fgMinuit = new TMinuit(8);
94
95   if (fPlot) fDebug = 1;
96 }
97
98 //_____________________________________________________________________________
99 AliMUONClusterFinderMLEM::~AliMUONClusterFinderMLEM()
100 {
101 /// Destructor
102   delete fgMinuit; fgMinuit = 0; delete fPixArray; fPixArray = 0;
103 //  delete fDraw;
104   delete fPreClusterFinder;
105   delete fSplitter;
106   AliInfo(Form("Total clusters %d AddVirtualPad needed %d",
107                fNClusters,fNAddVirtualPads));
108 }
109
110 //_____________________________________________________________________________
111 Bool_t 
112 AliMUONClusterFinderMLEM::Prepare(const AliMpVSegmentation* segmentations[2],
113                                   const AliMUONVDigitStore& digitStore)
114 {
115   /// Prepare for clustering
116 //  AliCodeTimerAuto("")
117   
118   for ( Int_t i = 0; i < 2; ++i )
119   {
120     fSegmentation[i] = segmentations[i];
121   }
122   
123   // Find out the DetElemId
124   fDetElemId = -1;
125   
126   TIter next(digitStore.CreateIterator());
127   AliMUONVDigit* d = static_cast<AliMUONVDigit*>(next());
128   
129   if (d)
130   {
131     fDetElemId = d->DetElemId();
132   }
133   
134   if ( fDetElemId < 0 )
135   {
136     AliWarning("Could not find DE. Probably no digits at all ?");
137     return kFALSE;
138   }
139   
140   delete fSplitter;
141   fSplitter = new AliMUONClusterSplitterMLEM(fDetElemId,fPixArray);
142   fSplitter->SetDebug(fDebug);
143     
144   // find out current event number, and reset the cluster number
145   fEventNumber = AliRunLoader::GetRunLoader()->GetEventNumber();
146   fClusterNumber = -1;
147   fClusterList.Delete();
148   
149   AliDebug(3,Form("EVT %d DE %d",fEventNumber,fDetElemId));
150   
151   return fPreClusterFinder->Prepare(segmentations,digitStore);
152 }
153
154 //_____________________________________________________________________________
155 AliMUONCluster* 
156 AliMUONClusterFinderMLEM::NextCluster()
157 {
158   /// Return next cluster
159 //  AliCodeTimerAuto("")
160   
161   // if the list of clusters is not void, pick one from there
162   TObject* o = fClusterList.At(++fClusterNumber);
163   if ( o != 0x0 ) return static_cast<AliMUONCluster*>(o);
164   
165   //FIXME : at this point, must check whether we've used all the digits
166   //from precluster : if not, let the preclustering know about those unused
167   //digits, so it can reuse them
168   
169   // if the cluster list is exhausted, we need to go to the next
170   // pre-cluster and treat it
171
172   fPreCluster = fPreClusterFinder->NextCluster();
173   
174   if (!fPreCluster)
175   {
176     // we are done
177     return 0x0;
178   }
179     
180   fClusterList.Delete(); // reset the list of clusters for this pre-cluster
181   fClusterNumber = -1; //AZ
182   
183   WorkOnPreCluster();
184
185   // WorkOnPreCluster may have used only part of the pads, so we check that
186   // now, and let the unused pads be reused by the preclustering...
187   
188   Int_t mult = fPreCluster->Multiplicity();
189   for ( Int_t i = 0; i < mult; ++i )
190   {
191     AliMUONPad* pad = fPreCluster->Pad(i);
192     if ( !pad->IsUsed() )
193     {
194       fPreClusterFinder->UsePad(*pad);
195     }
196   }
197   
198   return NextCluster();
199 }
200
201 //_____________________________________________________________________________
202 Bool_t
203 AliMUONClusterFinderMLEM::WorkOnPreCluster()
204 {
205   /// Starting from a precluster, builds a pixel array, and then
206   /// extract clusters from this array
207   
208   //  AliCodeTimerAuto("")      
209
210   if (fDebug) {
211     cout << " *** Event # " << AliRunLoader::GetRunLoader()->GetEventNumber() 
212          << " det. elem.: " << fDetElemId << endl;
213     for (Int_t j = 0; j < fPreCluster->Multiplicity(); ++j) {
214       AliMUONPad* pad = fPreCluster->Pad(j);
215       printf(" bbb %3d %1d %8.4f %8.4f %8.4f %8.4f %6.1f %3d %3d %2d %1d %1d \n",
216              j, pad->Cathode(), pad->Coord(0), pad->Coord(1), pad->DX()*2, pad->DY()*2,
217              pad->Charge(), pad->Ix(), pad->Iy(), pad->Status(), pad->IsReal(), pad->IsSaturated());
218     }
219   }
220
221   AliMUONCluster* cluster = CheckPrecluster(*fPreCluster);
222   if (!cluster) return kFALSE;
223
224   BuildPixArray(*cluster);
225   
226   if ( fPixArray->GetLast() < 0 )
227   {
228     AliDebug(1,"No pixel for the above cluster");
229     delete cluster;
230     return kFALSE;
231   }
232   
233   // Use MLEM for cluster finder
234   Int_t nMax = 1, localMax[100], maxPos[100];
235   Double_t maxVal[100];
236   
237   Int_t iSimple = 0, nInX = -1, nInY;
238   
239   PadsInXandY(*cluster,nInX, nInY);
240   
241   if (nInX < 4 && nInY < 4) 
242   {
243     iSimple = 1; // simple cluster
244   }
245   else 
246   {
247     nMax = FindLocalMaxima(fPixArray, localMax, maxVal); // for small clusters just to tag pixels
248     if (nMax > 1) {
249       if (cluster->Multiplicity() <= 50) nMax = 1; // for small clusters 
250       if (nMax > 1) TMath::Sort(nMax, maxVal, maxPos, kTRUE); // in descending order
251     }
252   }
253   
254   for (Int_t i = 0; i < nMax; ++i) 
255   {
256     if (nMax > 1) 
257     {
258       FindCluster(*cluster,localMax, maxPos[i]);
259     }
260
261     MainLoop(*cluster,iSimple);
262
263     if (i < nMax-1) 
264     {
265       Int_t mult = cluster->Multiplicity();
266       for (Int_t j = 0; j < mult; ++j) 
267       {
268         AliMUONPad* pad = cluster->Pad(j);
269         //if ( pad->Status() == 0 ) continue; // pad charge was not modified
270         if ( pad->Status() != fgkOver ) continue; // pad was not used
271         //pad->SetStatus(0);
272         pad->SetStatus(fgkZero);
273         pad->RevertCharge(); // use backup charge value
274       }
275     }
276   } // for (Int_t i=0; i<nMax;
277   //if (nMax > 1) ((TH2D*) gROOT->FindObject("anode"))->Delete();
278   delete ((TH2D*) gROOT->FindObject("anode"));
279   //TH2D *mlem = (TH2D*) gROOT->FindObject("mlem");
280   //if (mlem) mlem->Delete();
281   delete cluster;
282   return kTRUE;
283 }
284
285 //_____________________________________________________________________________
286 Bool_t 
287 AliMUONClusterFinderMLEM::Overlap(const AliMUONPad& pad, const AliMUONPad& pixel)
288 {
289   /// Check if the pad and the pixel overlaps
290
291   // make a fake pad from the pixel
292   AliMUONPad tmp(pad.DetElemId(),pad.Cathode(),pad.Ix(),pad.Iy(),
293                  pixel.Coord(0),pixel.Coord(1),
294                  pixel.Size(0),pixel.Size(1),0);
295   
296   return AliMUONPad::AreOverlapping(pad,tmp,fgkDecreaseSize);
297 }
298
299 //_____________________________________________________________________________
300 AliMUONCluster* 
301 AliMUONClusterFinderMLEM::CheckPrecluster(const AliMUONCluster& origCluster)
302 {
303   /// Check precluster in order to attempt to simplify it (mostly for
304   /// two-cathode preclusters)
305     
306   //  AliCodeTimerAuto("")
307
308   // Disregard small clusters (leftovers from splitting or noise)
309   if ((origCluster.Multiplicity()==1 || origCluster.Multiplicity()==2) &&
310       origCluster.Charge(0)+origCluster.Charge(1) < 10) 
311   { 
312     return 0x0;
313   }
314
315   //AliMUONCluster* cluster = static_cast<AliMUONCluster*>(origCluster.Clone());
316   AliMUONCluster* cluster = new AliMUONCluster(origCluster);
317
318   AliDebug(2,"Start of CheckPreCluster=");
319   //StdoutToAliDebug(2,cluster->Print("full"));
320
321   AliMUONCluster* rv(0x0);
322   
323   if (cluster->Multiplicity(0) && cluster->Multiplicity(1))
324   { 
325     rv = CheckPreclusterTwoCathodes(cluster);
326   }
327   else
328   {
329     rv = cluster;
330   }
331   return rv;
332 }
333
334 //_____________________________________________________________________________
335 AliMUONCluster*
336 AliMUONClusterFinderMLEM::CheckPreclusterTwoCathodes(AliMUONCluster* cluster)
337 {
338   /// Check two-cathode cluster
339   
340   Int_t npad = cluster->Multiplicity();
341   Int_t* flags = new Int_t[npad];
342   for (Int_t j = 0; j < npad; ++j) flags[j] = 0;
343   
344   // Check pad overlaps
345   for ( Int_t i = 0; i < npad; ++i) 
346   {
347     AliMUONPad* padi = cluster->Pad(i);
348     if ( padi->Cathode() != 0 ) continue;
349     for (Int_t j = i+1; j < npad; ++j) 
350     {
351       AliMUONPad* padj = cluster->Pad(j);
352       if ( padj->Cathode() != 1 ) continue;
353       if ( !AliMUONPad::AreOverlapping(*padi,*padj,fgkDecreaseSize) ) continue;
354       flags[i] = flags[j] = 1; // mark overlapped pads
355     } 
356   } 
357   
358   // Check if all pads overlap
359   Int_t nFlags=0;
360   for (Int_t i = 0; i < npad; ++i) 
361   {
362     if (!flags[i]) ++nFlags;
363   }
364   
365   if (nFlags > 0) 
366   {
367     // not all pads overlap.
368     if (fDebug) cout << " nFlags: " << nFlags << endl;
369     TObjArray toBeRemoved;
370     for (Int_t i = 0; i < npad; ++i) 
371     {
372       AliMUONPad* pad = cluster->Pad(i);
373       if (flags[i]) continue;
374       Int_t cath = pad->Cathode();
375       Int_t cath1 = TMath::Even(cath);
376       // Check for edge effect (missing pads on the _other_ cathode)
377       AliMpPad mpPad = fSegmentation[cath1]->PadByPosition(pad->Position(),kFALSE);
378       if (!mpPad.IsValid()) continue;
379       //if (nFlags == 1 && pad->Charge() < fgkZeroSuppression * 3) continue;
380       if (nFlags == 1 && pad->Charge() < 20) continue;
381       AliDebug(2,Form("Releasing the following pad : de,cath,ix,iy %d,%d,%d,%d charge %e",
382                       fDetElemId,pad->Cathode(),pad->Ix(),pad->Iy(),pad->Charge()));
383       toBeRemoved.AddLast(pad);
384       fPreCluster->Pad(i)->Release();
385     }
386     Int_t nRemove = toBeRemoved.GetEntriesFast();
387     for ( Int_t i = 0; i < nRemove; ++i )
388     {
389       cluster->RemovePad(static_cast<AliMUONPad*>(toBeRemoved.UncheckedAt(i)));
390     }
391   } 
392   
393   // Check correlations of cathode charges
394   if ( !cluster->IsSaturated() && cluster->ChargeAsymmetry() > 1 )
395   {
396     // big difference
397     Int_t cathode = cluster->MaxRawChargeCathode();
398     Int_t imin(-1);
399     Int_t imax(-1);
400     Double_t cmax(0);
401     Double_t cmin(1E9);
402     
403     // get min and max pad charges on the cathode opposite to the 
404     // max pad (given by MaxRawChargeCathode())
405     //
406     Int_t mult = cluster->Multiplicity();
407     for ( Int_t i = 0; i < mult; ++i )
408     {
409       AliMUONPad* pad = cluster->Pad(i);
410       if ( pad->Cathode() != cathode || !pad->IsReal() )
411       {
412         // only consider pads in the opposite cathode, and
413         // only consider real pads (i.e. exclude the virtual ones)
414         continue;
415       }
416       if ( pad->Charge() < cmin )
417       {
418         cmin = pad->Charge();
419         imin = i;
420         if (imax < 0) {
421           imax = imin;
422           cmax = cmin;
423         }
424       }
425       else if ( pad->Charge() > cmax )
426       {
427         cmax = pad->Charge();
428         imax = i;
429       }      
430     }
431     AliDebug(2,Form("Pad imin,imax %d,%d cmin,cmax %e,%e",
432                     imin,imax,cmin,cmax));
433     //
434     // arrange pads according to their distance to the max, normalized
435     // to the pad size
436     Double_t* dist = new Double_t[mult];
437     Double_t dxMin(1E9);
438     Double_t dyMin(1E9);
439     Double_t dmin(0);
440     
441     AliMUONPad* padmax = cluster->Pad(imax);
442     
443     for ( Int_t i = 0; i < mult; ++i )
444     {
445       dist[i] = 0.0;
446       if ( i == imax) continue;
447       AliMUONPad* pad = cluster->Pad(i);
448       if ( pad->Cathode() != cathode || !pad->IsReal() ) continue;
449       Double_t dx = (pad->X()-padmax->X())/padmax->DX()/2.0;
450       Double_t dy = (pad->Y()-padmax->Y())/padmax->DY()/2.0;
451       dist[i] = TMath::Sqrt(dx*dx+dy*dy);
452       if ( i == imin )
453       {
454         dmin = dist[i] + 1E-3; // distance to the pad with minimum charge
455         dxMin = dx;
456         dyMin = dy;
457       }      
458     }
459     
460     TMath::Sort(mult,dist,flags,kFALSE); // in ascending order
461     Double_t xmax(-1), distPrev(999);
462     TObjArray toBeRemoved;
463     
464     for ( Int_t i = 0; i < mult; ++i )
465     {
466       Int_t indx = flags[i];
467       AliMUONPad* pad = cluster->Pad(indx);
468       if ( pad->Cathode() != cathode || !pad->IsReal() ) continue;
469       if ( dist[indx] > dmin )
470       {
471         // farther than the minimum pad
472         Double_t dx = (pad->X()-padmax->X())/padmax->DX()/2.0;
473         Double_t dy = (pad->Y()-padmax->Y())/padmax->DY()/2.0;
474         dx *= dxMin;
475         dy *= dyMin;
476         if (dx >= 0 && dy >= 0) continue;
477         if (TMath::Abs(dx) > TMath::Abs(dy) && dx >= 0) continue;
478         if (TMath::Abs(dy) > TMath::Abs(dx) && dy >= 0) continue;        
479       }
480       if (dist[indx] > distPrev + 1) break; // overstepping empty pads
481       if ( pad->Charge() <= cmax || TMath::Abs(dist[indx]-xmax) < 1E-3 )
482       {
483         // release pad
484         if (TMath::Abs(dist[indx]-xmax) < 1.e-3) 
485         {
486           cmax = TMath::Max(pad->Charge(),cmax);
487         }
488         else
489         {
490           cmax = pad->Charge();
491         }
492         xmax = dist[indx];
493         distPrev = dist[indx];
494         AliDebug(2,Form("Releasing the following pad : de,cath,ix,iy %d,%d,%d,%d charge %e",
495                         fDetElemId,pad->Cathode(),pad->Ix(),pad->Iy(),
496                         pad->Charge()));
497   
498         toBeRemoved.AddLast(pad);
499         fPreCluster->Pad(indx)->Release();
500       }
501     }
502     Int_t nRemove = toBeRemoved.GetEntriesFast();
503     for ( Int_t i = 0; i < nRemove; ++i )
504     {
505       cluster->RemovePad(static_cast<AliMUONPad*>(toBeRemoved.UncheckedAt(i)));
506     }    
507     delete[] dist;
508   }
509   
510   delete[] flags;
511   
512   AliDebug(2,"End of CheckPreClusterTwoCathodes=");
513   //StdoutToAliDebug(2,cluster->Print("full"));
514
515   return cluster;    
516 }
517
518 //_____________________________________________________________________________
519 void
520 AliMUONClusterFinderMLEM::CheckOverlaps()
521 {
522   /// For debug only : check if some pixels overlap...
523   
524   Int_t nPix = fPixArray->GetLast()+1;
525   Int_t dummy(0);
526   
527   for ( Int_t i = 0; i < nPix; ++i )
528   {
529     AliMUONPad* pixelI = Pixel(i);
530     AliMUONPad pi(dummy,dummy,dummy,dummy,
531                   pixelI->Coord(0),pixelI->Coord(1),
532                   pixelI->Size(0),pixelI->Size(1),0.0);
533     
534     for ( Int_t j = i+1; j < nPix; ++j )
535     {
536       AliMUONPad* pixelJ = Pixel(j);
537       AliMUONPad pj(dummy,dummy,dummy,dummy,
538                     pixelJ->Coord(0),pixelJ->Coord(1),
539                     pixelJ->Size(0),pixelJ->Size(1),0.0);  
540       AliMpArea area;
541       
542       if ( AliMUONPad::AreOverlapping(pi,pj,fgkDecreaseSize,area) )
543       {
544         AliInfo(Form("The following 2 pixels (%d and %d) overlap !",i,j));
545         /*
546         StdoutToAliInfo(pixelI->Print();
547                         cout << " Surface = " << pixelI->Size(0)*pixelI->Size(1)*4 << endl;
548                         pixelJ->Print();
549                         cout << " Surface = " << pixelJ->Size(0)*pixelJ->Size(1)*4 << endl;
550                         cout << " Area surface = " << area.Dimensions().X()*area.Dimensions().Y()*4 << endl;
551                         cout << "-------" << endl;
552                         );
553         */        
554       }
555     }    
556   }
557 }
558
559 //_____________________________________________________________________________
560 void AliMUONClusterFinderMLEM::BuildPixArray(AliMUONCluster& cluster)
561 {
562   /// Build pixel array for MLEM method
563   
564   Int_t npad = cluster.Multiplicity();
565   if (npad<=0) 
566   {
567     AliWarning("Got no pad at all ?!");
568   }
569   
570   fPixArray->Delete();
571   BuildPixArrayOneCathode(cluster);
572   
573   Int_t nPix = fPixArray->GetLast()+1;
574   
575 //  AliDebug(2,Form("nPix after BuildPixArray=%d",nPix));
576   
577   if ( nPix > npad ) 
578   {
579 //    AliDebug(2,Form("Will trim number of pixels to number of pads"));
580     
581     // Too many pixels - sort and remove pixels with the lowest signal
582     fPixArray->Sort();
583     for ( Int_t i = npad; i < nPix; ++i ) 
584     {
585       RemovePixel(i);
586     }
587     fPixArray->Compress();
588   } // if (nPix > npad)
589
590 //  StdoutToAliDebug(2,cout << "End of BuildPixelArray:" << endl;
591 //                   fPixArray->Print(););
592   //CheckOverlaps();//FIXME : this is for debug only. Remove it.
593 }
594
595 //_____________________________________________________________________________
596 void AliMUONClusterFinderMLEM::BuildPixArrayOneCathode(AliMUONCluster& cluster)
597 {
598   /// Build the pixel array
599
600 //  AliDebug(2,Form("cluster.Multiplicity=%d",cluster.Multiplicity()));
601
602   TVector2 dim = cluster.MinPadDimensions (-1, kFALSE);
603   Double_t width[2] = {dim.X(), dim.Y()}, xy0[2];
604   Int_t found[2] = {0}, mult = cluster.Multiplicity();
605
606   for ( Int_t i = 0; i < mult; ++i) {
607     AliMUONPad* pad = cluster.Pad(i);
608     for (Int_t j = 0; j < 2; ++j) {
609       if (found[j] == 0 && TMath::Abs(pad->Size(j)-width[j]) < fgkDistancePrecision) { 
610         xy0[j] = pad->Coord(j);
611         found[j] = 1;
612       }
613     }
614     if (found[0] && found[1]) break;
615   }
616
617   Double_t min[2], max[2];
618   Int_t cath0 = 0, cath1 = 1;
619   if (cluster.Multiplicity(0) == 0) cath0 = 1;
620   else if (cluster.Multiplicity(1) == 0) cath1 = 0;
621
622   TVector2 leftDown = cluster.Area(cath0).LeftDownCorner();
623   TVector2 rightUp = cluster.Area(cath0).RightUpCorner();
624   min[0] = leftDown.X();
625   min[1] = leftDown.Y();
626   max[0] = rightUp.X();
627   max[1] = rightUp.Y();
628   if (cath1 != cath0) {
629     leftDown = cluster.Area(cath1).LeftDownCorner();
630     rightUp = cluster.Area(cath1).RightUpCorner();
631     min[0] = TMath::Max (min[0], leftDown.X());
632     min[1] = TMath::Max (min[1], leftDown.Y());
633     max[0] = TMath::Min (max[0], rightUp.X());
634     max[1] = TMath::Min (max[1], rightUp.Y());
635   }
636
637   // Adjust limits
638   //width[0] /= 2; width[1] /= 2; // just for check
639   Int_t nbins[2];
640   for (Int_t i = 0; i < 2; ++i) {
641     Double_t dist = (min[i] - xy0[i]) / width[i] / 2;
642     if (TMath::Abs(dist) < 1.e-6) dist = -1.e-6;
643     min[i] = xy0[i] + (TMath::Nint(dist-TMath::Sign(1.e-6,dist)) 
644                        + TMath::Sign(0.5,dist)) * width[i] * 2;
645     nbins[i] = TMath::Nint ((max[i] - min[i]) / width[i] / 2);
646     if (nbins[i] == 0) ++nbins[i];
647     max[i] = min[i] + nbins[i] * width[i] * 2;
648     //cout << dist << " " << min[i] << " " << max[i] << " " << nbins[i] << endl;
649   }
650
651   // Book histogram
652   TH2D *hist1 = new TH2D ("Grid", "", nbins[0], min[0], max[0], nbins[1], min[1], max[1]);
653   TH2D *hist2 = new TH2D ("Entries", "", nbins[0], min[0], max[0], nbins[1], min[1], max[1]);
654   TAxis *xaxis = hist1->GetXaxis();
655   TAxis *yaxis = hist1->GetYaxis();
656
657   // Fill histogram
658   for ( Int_t i = 0; i < mult; ++i) {
659     AliMUONPad* pad = cluster.Pad(i);
660     Int_t ix0 = xaxis->FindBin(pad->X());
661     Int_t iy0 = yaxis->FindBin(pad->Y());
662     PadOverHist(0, ix0, iy0, pad);
663   }
664
665   // Store pixels
666   for (Int_t i = 1; i <= nbins[0]; ++i) {
667     Double_t x = xaxis->GetBinCenter(i);
668     for (Int_t j = 1; j <= nbins[1]; ++j) {
669       if (hist2->GetCellContent(i,j) < 0.1) continue;
670       //if (hist2->GetCellContent(i,j) < 1.1 && cluster.Multiplicity(0) && 
671       //  cluster.Multiplicity(1)) continue;
672       if (cath0 != cath1) {
673         // Two-sided cluster
674         Double_t cont = hist2->GetCellContent(i,j);
675         if (cont < 999.) continue;
676         if (cont-Int_t(cont/1000.)*1000. < 0.5) continue;
677       }
678       Double_t y = yaxis->GetBinCenter(j);
679       Double_t charge = hist1->GetCellContent(i,j);
680       AliMUONPad* pixPtr = new AliMUONPad(x, y, width[0], width[1], charge);
681       fPixArray->Add(pixPtr);
682     }  
683   }
684   //*
685   if (fPixArray->GetEntriesFast() == 1) {
686     // Split pixel into 2
687     AliMUONPad* pixPtr = static_cast<AliMUONPad*> (fPixArray->UncheckedAt(0));
688     pixPtr->SetSize(0,width[0]/2.);
689     pixPtr->Shift(0,-width[0]/4.);
690     pixPtr = new AliMUONPad(pixPtr->X()+width[0], pixPtr->Y(), width[0]/2., width[1], pixPtr->Charge());
691     fPixArray->Add(pixPtr);
692   }
693   //*/
694   //fPixArray->Print();
695   delete hist1;
696   delete hist2;
697 }
698
699 //_____________________________________________________________________________
700 void AliMUONClusterFinderMLEM::PadOverHist(Int_t idir, Int_t ix0, Int_t iy0, AliMUONPad *pad)
701 {
702   /// "Span" pad over histogram in the direction idir
703
704   TH2D *hist1 = static_cast<TH2D*> (gROOT->FindObject("Grid"));
705   TH2D *hist2 = static_cast<TH2D*> (gROOT->FindObject("Entries"));
706   TAxis *axis = idir == 0 ? hist1->GetXaxis() : hist1->GetYaxis();
707   Int_t nbins = axis->GetNbins(), cath = pad->Cathode();
708   Double_t bin = axis->GetBinWidth(1), amask = TMath::Power(1000.,cath*1.);
709
710   Int_t nbinPad = (Int_t)(pad->Size(idir)/bin*2+fgkDistancePrecision) + 1; // number of bins covered by pad
711
712   for (Int_t i = 0; i < nbinPad; ++i) {
713     Int_t ixy = idir == 0 ? ix0 + i : iy0 + i;
714     if (ixy > nbins) break;
715     Double_t lowEdge = axis->GetBinLowEdge(ixy);
716     if (lowEdge + fgkDistancePrecision > pad->Coord(idir) + pad->Size(idir)) break;
717     if (idir == 0) PadOverHist(1, ixy, iy0, pad); // span in the other direction
718     else {
719       // Fill histogram
720       Double_t cont = pad->Charge();
721       if (hist2->GetCellContent(ix0, ixy) > 0.1) 
722         cont = TMath::Min (hist1->GetCellContent(ix0, ixy), cont);
723       hist1->SetCellContent(ix0, ixy, cont);
724       //hist2->SetCellContent(ix0, ixy, hist2->GetCellContent(ix0, ixy)+1);
725       hist2->SetCellContent(ix0, ixy, hist2->GetCellContent(ix0, ixy)+amask);
726     }
727   }
728
729   for (Int_t i = -1; i > -nbinPad; --i) {
730     Int_t ixy = idir == 0 ? ix0 + i : iy0 + i;
731     if (ixy < 1) break;
732     Double_t upEdge = axis->GetBinUpEdge(ixy);
733     if (upEdge - fgkDistancePrecision < pad->Coord(idir) - pad->Size(idir)) break;
734     if (idir == 0) PadOverHist(1, ixy, iy0, pad); // span in the other direction
735     else {
736       // Fill histogram
737       Double_t cont = pad->Charge();
738       if (hist2->GetCellContent(ix0, ixy) > 0.1) 
739         cont = TMath::Min (hist1->GetCellContent(ix0, ixy), cont);
740       hist1->SetCellContent(ix0, ixy, cont);
741       //hist2->SetCellContent(ix0, ixy, hist2->GetCellContent(ix0, ixy)+1);
742       hist2->SetCellContent(ix0, ixy, hist2->GetCellContent(ix0, ixy)+amask);
743     }
744   }
745 }
746
747 //_____________________________________________________________________________
748 void
749 AliMUONClusterFinderMLEM::Plot(const char* basename)
750 {
751   /// Make a plot and save it as png
752   
753   return; //AZ
754   if (!fPlot) return;
755   
756   TCanvas* c = new TCanvas("MLEM","MLEM",800,600);
757   c->Draw();
758   Draw();
759   c->Modified();
760   c->Update();
761   c->Print(Form("%s.EVT%d.DE%d.CLU%d.png",basename,fEventNumber,
762                 fDetElemId,fClusterNumber));
763 }
764
765 //_____________________________________________________________________________
766 void
767 AliMUONClusterFinderMLEM::ComputeCoefficients(AliMUONCluster& cluster,
768                                               Double_t* coef,
769                                               Double_t* probi)
770 {
771   /// Compute coefficients needed for MLEM algorithm
772   
773   Int_t nPix = fPixArray->GetLast()+1;
774   
775   //memset(probi,0,nPix*sizeof(Double_t));
776   for (Int_t j = 0; j < nPix; ++j) probi[j] = 0.;
777
778   Int_t mult = cluster.Multiplicity();
779   for ( Int_t j = 0; j < mult; ++j ) 
780   {
781     AliMUONPad* pad = cluster.Pad(j);
782     Int_t indx = j*nPix;
783   
784     for ( Int_t ipix = 0; ipix < nPix; ++ipix ) 
785     {
786       Int_t indx1 = indx + ipix;
787       //if (pad->Status() < 0) 
788       if (pad->Status() != fgkZero) 
789       {   
790         coef[indx1] = 0; 
791         continue; 
792       }
793       AliMUONPad* pixPtr = Pixel(ipix);
794       // coef is the charge (given by Mathieson integral) on pad, assuming
795       // the Mathieson is center at pixel.
796       coef[indx1] = fSplitter->ChargeIntegration(pixPtr->Coord(0), pixPtr->Coord(1), *pad);  
797 //      AliDebug(2,Form("pad=(%d,%d,%e,%e,%e,%e) pix=(%e,%e,%e,%e) coef %e",
798 //                      pad->Ix(),pad->Iy(),
799 //                      pad->X(),pad->Y(),
800 //                      pad->DX(),pad->DY(),
801 //                      pixPtr->Coord(0),pixPtr->Coord(1), 
802 //                      pixPtr->Size(0),pixPtr->Size(1),
803 //                      coef[indx1]));
804       
805       probi[ipix] += coef[indx1];
806     } 
807   } 
808 }
809
810 //_____________________________________________________________________________
811 Bool_t AliMUONClusterFinderMLEM::MainLoop(AliMUONCluster& cluster, Int_t iSimple)
812 {
813   /// Repeat MLEM algorithm until pixel size becomes sufficiently small
814   
815   //  AliCodeTimerAuto("")
816   
817   Int_t nPix = fPixArray->GetLast()+1;
818
819   AliDebug(2,Form("nPix=%d iSimple=%d, precluster=",nPix,iSimple));
820   //StdoutToAliDebug(2,cluster.Print("full"););
821
822   if ( nPix < 0 )
823   {
824     AliDebug(1,"No pixels, why am I here then ?");
825   }
826   
827   AddVirtualPad(cluster); // add virtual pads if necessary
828   
829   Int_t npadTot = cluster.Multiplicity();
830   Int_t npadOK = 0;
831   for (Int_t i = 0; i < npadTot; ++i) 
832   {
833     //if (cluster.Pad(i)->Status() == 0) ++npadOK;
834     if (cluster.Pad(i)->Status() == fgkZero) ++npadOK;
835   }
836
837   TH2D* mlem(0x0);
838   Double_t* coef(0x0);
839   Double_t* probi(0x0);
840   Int_t lc(0); // loop counter
841   
842   //Plot("mlem.start");
843   AliMUONPad* pixPtr = Pixel(0);
844   Double_t xylim[4] = {pixPtr->X(), -pixPtr->X(), pixPtr->Y(), -pixPtr->Y()};
845
846   while (1) 
847   {
848     ++lc;
849     mlem = (TH2D*) gROOT->FindObject("mlem");
850     delete mlem;
851     
852     AliDebug(2,Form("lc %d nPix %d(%d) npadTot %d npadOK %d",lc,nPix,fPixArray->GetLast()+1,npadTot,npadOK));
853     AliDebug(2,Form("EVT%d PixArray=",fEventNumber));
854     //StdoutToAliDebug(2,fPixArray->Print("","full"));
855         
856     coef = new Double_t [npadTot*nPix];
857     probi = new Double_t [nPix];
858
859     // Calculate coefficients and pixel visibilities
860     ComputeCoefficients(cluster,coef,probi);
861
862     for (Int_t ipix = 0; ipix < nPix; ++ipix) 
863     {
864       if (probi[ipix] < 0.01) 
865       {
866         AliMUONPad* pixel = Pixel(ipix);
867         AliDebug(2,Form("Setting the following pixel to invisible as its probi<0.01:"));
868         //StdoutToAliDebug(2,cout << Form(" -- ipix %3d --- "); pixel->Print(););
869         pixel->SetCharge(0); // "invisible" pixel
870       }
871     }
872     
873     // MLEM algorithm
874     Mlem(cluster,coef, probi, 15);
875
876     // Find histogram limits for the 1'st pass only - for others computed below
877     if (lc == 1) {
878       for ( Int_t ipix = 1; ipix < nPix; ++ipix ) 
879         {
880           pixPtr = Pixel(ipix);
881           for ( Int_t i = 0; i < 2; ++i ) 
882             {
883               Int_t indx = i * 2;
884               if (pixPtr->Coord(i) < xylim[indx]) xylim[indx] = pixPtr->Coord(i); 
885               else if (-pixPtr->Coord(i) < xylim[indx+1]) xylim[indx+1] = -pixPtr->Coord(i); 
886             }
887         }
888     } else pixPtr = Pixel(0);
889
890     for (Int_t i = 0; i < 4; i++) 
891     {
892       xylim[i] -= pixPtr->Size(i/2); 
893     }
894     
895     Int_t nx = TMath::Nint ((-xylim[1]-xylim[0])/pixPtr->Size(0)/2);
896     Int_t ny = TMath::Nint ((-xylim[3]-xylim[2])/pixPtr->Size(1)/2);
897
898     //StdoutToAliDebug(2,cout << "pixel used for nx,ny computation : "; pixPtr->Print(););
899     AliDebug(2,Form("lc %d pixPtr size = %e,%e nx,ny=%d,%d xylim=%e,%e,%e,%e",
900                     lc,pixPtr->Size(0),pixPtr->Size(1),nx,ny,
901                     xylim[0],-xylim[1],xylim[2],-xylim[3]
902                     ));
903     
904     mlem = new TH2D("mlem","mlem",nx,xylim[0],-xylim[1],ny,xylim[2],-xylim[3]);
905
906     for (Int_t ipix = 0; ipix < nPix; ++ipix) 
907     {
908       AliMUONPad* pixPtr = Pixel(ipix);
909       mlem->Fill(pixPtr->Coord(0),pixPtr->Coord(1),pixPtr->Charge());
910     }
911
912     // Check if the total charge of pixels is too low
913     Double_t qTot = 0;
914     for ( Int_t i = 0; i < nPix; ++i) 
915     {
916       qTot += Pixel(i)->Charge();
917     }
918     
919     if ( qTot < 1.e-4 || ( npadOK < 3 && qTot < 7 ) ) 
920     {
921       AliDebug(1,Form("Deleting the above cluster (charge %e too low, npadOK=%d)",qTot,npadOK));
922       delete [] coef; 
923       delete [] probi; 
924       fPixArray->Delete(); 
925       for ( Int_t i = 0; i < npadTot; ++i) 
926       {
927         AliMUONPad* pad = cluster.Pad(i);
928         //if ( pad->Status() == 0) pad->SetStatus(-1);
929         if ( pad->Status() == fgkZero) pad->SetStatus(fgkOver);
930       }
931       return kFALSE; 
932     }
933
934     if (iSimple) 
935     {
936       // Simple cluster - skip further passes thru EM-procedure
937       Simple(cluster);
938       delete [] coef; 
939       delete [] probi; 
940       fPixArray->Delete(); 
941       return kTRUE;
942     }
943
944     // Calculate position of the center-of-gravity around the maximum pixel
945     Double_t xyCOG[2];
946     FindCOG(mlem, xyCOG);
947
948     if (TMath::Min(pixPtr->Size(0),pixPtr->Size(1)) < 0.07 && 
949         pixPtr->Size(0) > pixPtr->Size(1)) break;
950
951     // Sort pixels according to the charge
952     MaskPeaks(1); // mask local maxima
953     fPixArray->Sort();
954     MaskPeaks(0); // unmask local maxima
955     Double_t pixMin = 0.01*Pixel(0)->Charge();
956     pixMin = TMath::Min(pixMin,50.);
957
958     // Decrease pixel size and shift pixels to make them centered at 
959     // the maximum one
960     Int_t indx = (pixPtr->Size(0)>pixPtr->Size(1)) ? 0 : 1;
961     Int_t ix(1);
962     Double_t width = 0;
963     Double_t shift[2] = { 0.0, 0.0 };
964     for (Int_t i = 0; i < 4; ++i) xylim[i] = 999;
965     Int_t nPix1 = nPix; 
966     nPix = 0;
967     for (Int_t ipix = 0; ipix < nPix1; ++ipix) 
968     {
969       AliMUONPad* pixPtr = Pixel(ipix);
970       if ( nPix >= npadOK  // too many pixels already
971            ||
972            pixPtr->Charge() < pixMin && pixPtr->Status() != fgkMustKeep // too low charge
973            ) 
974       { 
975         RemovePixel(ipix);
976         continue;
977       }
978       for (Int_t i = 0; i < 2; ++i) 
979       {
980         if (!i) 
981         {
982           pixPtr->SetCharge(10);
983           pixPtr->SetSize(indx, pixPtr->Size(indx)/2);
984           width = -pixPtr->Size(indx);
985           pixPtr->Shift(indx, width);
986           // Shift pixel position
987           if (ix) 
988           {
989             ix = 0;
990             for (Int_t j = 0; j < 2; ++j) 
991             {
992               shift[j] = pixPtr->Coord(j) - xyCOG[j];
993               shift[j] -= ((Int_t)(shift[j]/pixPtr->Size(j)/2))*pixPtr->Size(j)*2;
994             }
995           } // if (ix)
996           pixPtr->Shift(0, -shift[0]);
997           pixPtr->Shift(1, -shift[1]);
998           ++nPix;
999         } 
1000         else if (nPix < npadOK)
1001         {
1002           pixPtr = new AliMUONPad(*pixPtr);
1003           pixPtr->Shift(indx, -2*width);
1004           pixPtr->SetStatus(fgkZero);
1005           fPixArray->Add(pixPtr);
1006           ++nPix;
1007         } 
1008         else continue; // skip adjustment of histo limits
1009         for (Int_t j = 0; j < 4; ++j) 
1010         {
1011           xylim[j] = TMath::Min (xylim[j], (j%2 ? -1 : 1)*pixPtr->Coord(j/2));
1012         }
1013       } // for (Int_t i=0; i<2;
1014     } // for (Int_t ipix=0;
1015     
1016     fPixArray->Compress();
1017
1018     AliDebug(2,Form("After shift:"));
1019     //StdoutToAliDebug(2,fPixArray->Print("","full"););
1020     //Plot(Form("mlem.lc%d",lc+1));
1021     
1022     AliDebug(2,Form(" xyCOG=%9.6f %9.6f xylim=%9.6f,%9.6f,%9.6f,%9.6f",
1023                     xyCOG[0],xyCOG[1],
1024                     xylim[0],xylim[1],
1025                     xylim[2],xylim[3]));
1026
1027     if (nPix < npadOK)
1028     {
1029       AliMUONPad* pixPtr = Pixel(0);
1030       // add pixels if the maximum is at the limit of pixel area:
1031       // start from Y-direction
1032       Int_t j = 0;
1033       for (Int_t i = 3; i > -1; --i) 
1034       {
1035         if (nPix < npadOK && 
1036             TMath::Abs((i%2 ? -1 : 1)*xylim[i]-xyCOG[i/2]) < pixPtr->Size(i/2)) 
1037         {
1038           //AliMUONPad* p = static_cast<AliMUONPad*>(pixPtr->Clone());
1039           AliMUONPad* p = new AliMUONPad(*pixPtr);
1040           p->SetCoord(i/2, xyCOG[i/2]+(i%2 ? 2:-2)*pixPtr->Size(i/2));
1041           xylim[i] = p->Coord(i/2) * (i%2 ? -1 : 1); // update histo limits
1042           j = TMath::Even (i/2);
1043           p->SetCoord(j, xyCOG[j]);
1044           AliDebug(2,Form("Adding pixel on the edge (i=%d) ",i));
1045           //StdoutToAliDebug(2,cout << " ---- "; 
1046           //               p->Print("corners"););
1047           fPixArray->Add(p);
1048           ++nPix;
1049         }
1050       }
1051     } 
1052     nPix = fPixArray->GetEntriesFast();
1053     delete [] coef; 
1054     delete [] probi; 
1055   } // while (1)
1056
1057   AliDebug(2,Form("At the end of while loop nPix=%d : ",fPixArray->GetLast()+1));
1058   //StdoutToAliDebug(2,fPixArray->Print("","full"););
1059
1060   // remove pixels with low signal or low visibility
1061   // Cuts are empirical !!!
1062   Double_t thresh = TMath::Max (mlem->GetMaximum()/100.,1.);
1063   thresh = TMath::Min (thresh,50.);
1064   Double_t charge = 0;
1065
1066   // Mark pixels which should be removed
1067   for (Int_t i = 0; i < nPix; ++i) 
1068   {
1069     AliMUONPad* pixPtr = Pixel(i);
1070     charge = pixPtr->Charge();
1071     if (charge < thresh) 
1072     {
1073       pixPtr->SetCharge(-charge);
1074     }
1075   }
1076
1077   // Move charge of removed pixels to their nearest neighbour (to keep total charge the same)
1078   Int_t near = 0;
1079   for (Int_t i = 0; i < nPix; ++i) 
1080   {
1081     AliMUONPad* pixPtr = Pixel(i);
1082     charge = pixPtr->Charge();
1083     if (charge > 0) continue;
1084     near = FindNearest(pixPtr);
1085     pixPtr->SetCharge(0);
1086     probi[i] = 0; // make it "invisible"
1087     AliMUONPad* pnear = Pixel(near);
1088     pnear->SetCharge(pnear->Charge() + (-charge));
1089   }
1090   Mlem(cluster,coef,probi,2);
1091   
1092   AliDebug(2,Form("Before splitting nPix=%d EVT %d DE %d",fPixArray->GetLast()+1,fEventNumber,fDetElemId));
1093   //StdoutToAliDebug(2,fPixArray->Print("","full"););
1094   //Plot("mlem.beforesplit");
1095   
1096   // Update histogram
1097   for (Int_t i = 0; i < nPix; ++i) 
1098   {
1099     AliMUONPad* pixPtr = Pixel(i);
1100     Int_t ix = mlem->GetXaxis()->FindBin(pixPtr->Coord(0));
1101     Int_t iy = mlem->GetYaxis()->FindBin(pixPtr->Coord(1));
1102     mlem->SetBinContent(ix, iy, pixPtr->Charge());
1103   }
1104
1105   // Try to split into clusters
1106   Bool_t ok = kTRUE;
1107   if (mlem->GetSum() < 1) 
1108   {
1109     ok = kFALSE;
1110   }
1111   else 
1112   {
1113     fSplitter->Split(cluster,mlem,coef,fClusterList);
1114   }
1115   
1116   delete [] coef; 
1117   delete [] probi; 
1118   fPixArray->Delete(); 
1119   
1120   return ok;
1121 }
1122
1123 //_____________________________________________________________________________
1124 void AliMUONClusterFinderMLEM::MaskPeaks(Int_t mask)
1125 {
1126   /// Mask/unmask pixels corresponding to local maxima (add/subtract 10000 to their charge
1127   /// - to avoid loosing low charge pixels after sorting)
1128
1129   for (Int_t i = 0; i < fPixArray->GetEntriesFast(); ++i) {
1130     AliMUONPad* pix = Pixel(i);
1131     if (pix->Status() == fgkMustKeep) {
1132       if (mask == 1) pix->SetCharge(pix->Charge()+10000.);
1133       else pix->SetCharge(pix->Charge()-10000.);
1134     }
1135   }
1136 }
1137
1138 //_____________________________________________________________________________
1139 void AliMUONClusterFinderMLEM::Mlem(AliMUONCluster& cluster, 
1140                                     Double_t* coef, Double_t* probi, 
1141                                     Int_t nIter)
1142 {
1143   /// Use MLEM to find pixel charges
1144   
1145   Int_t nPix = fPixArray->GetEntriesFast();
1146
1147   Int_t npad = cluster.Multiplicity();
1148
1149   Double_t* probi1 = new Double_t[nPix];
1150   Double_t probMax = TMath::MaxElement(nPix,probi);
1151   
1152   for (Int_t iter = 0; iter < nIter; ++iter) 
1153   {
1154     // Do iterations
1155     for (Int_t ipix = 0; ipix < nPix; ++ipix) 
1156     {
1157       Pixel(ipix)->SetChargeBackup(0);
1158       // Correct each pixel
1159       if (probi[ipix] < 0.01) continue; // skip "invisible" pixel
1160       Double_t sum = 0;
1161       probi1[ipix] = probMax;
1162       for (Int_t j = 0; j < npad; ++j) 
1163       {
1164         AliMUONPad* pad = cluster.Pad(j);
1165         //if (pad->Status() < 0) continue; 
1166         if (pad->Status() != fgkZero) continue; 
1167         Double_t sum1 = 0;
1168         Int_t indx1 = j*nPix;
1169         Int_t indx = indx1 + ipix;
1170         // Calculate expectation
1171         for (Int_t i = 0; i < nPix; ++i) 
1172         {
1173           sum1 += Pixel(i)->Charge()*coef[indx1+i];
1174           //cout << i << " " << Pixel(i)->Charge() << " " << coef[indx1+i] << endl;
1175         } 
1176         if ( pad->IsSaturated() && sum1 > pad->Charge() ) 
1177         { 
1178           // correct for pad charge overflows
1179           probi1[ipix] -= coef[indx]; 
1180           continue; 
1181           //sum1 = pad->Charge();
1182         } 
1183
1184         if (sum1 > 1.e-6) sum += pad->Charge()*coef[indx]/sum1;
1185         //if (coef[indx] > 1.e-6) sum += pad->Charge()*coef[indx]/sum1;
1186       } // for (Int_t j=0;
1187       AliMUONPad* pixPtr = Pixel(ipix);
1188       if (probi1[ipix] > 1.e-6) 
1189       {
1190         //AZ pixPtr->SetCharge(pixPtr->Charge()*sum/probi1[ipix]);
1191         pixPtr->SetChargeBackup(pixPtr->Charge()*sum/probi1[ipix]);
1192       }
1193       //cout << " xxx " << ipix << " " << pixPtr->Charge() << " " << pixPtr->ChargeBackup() << " " << sum << " " << probi1[ipix] << endl;
1194     } // for (Int_t ipix=0;
1195     Double_t qTot = 0;
1196     for (Int_t i = 0; i < nPix; ++i) {
1197       AliMUONPad* pixPtr = Pixel(i);
1198       pixPtr->RevertCharge();
1199       qTot += pixPtr->Charge();
1200     }
1201     if (qTot < 1.e-6) {
1202       // Can happen in clusters with large number of overflows - speeding up 
1203       delete [] probi1;
1204       return;
1205     }
1206   } // for (Int_t iter=0;
1207   delete [] probi1;
1208 }
1209
1210 //_____________________________________________________________________________
1211 void AliMUONClusterFinderMLEM::FindCOG(TH2D *mlem, Double_t *xyc)
1212 {
1213   /// Calculate position of the center-of-gravity around the maximum pixel
1214
1215   Int_t ixmax, iymax, ix, nsumx=0, nsumy=0, nsum=0;
1216   Int_t i1 = -9, j1 = -9;
1217   mlem->GetMaximumBin(ixmax,iymax,ix);
1218   Int_t nx = mlem->GetNbinsX();
1219   Int_t ny = mlem->GetNbinsY();
1220   Double_t thresh = mlem->GetMaximum()/10;
1221   Double_t x, y, cont, xq=0, yq=0, qq=0;
1222   
1223   Int_t ie = TMath::Min(ny,iymax+1), je = TMath::Min(nx,ixmax+1);
1224   for (Int_t i = TMath::Max(1,iymax-1); i <= ie; ++i) {
1225     y = mlem->GetYaxis()->GetBinCenter(i);
1226     for (Int_t j = TMath::Max(1,ixmax-1); j <= je; ++j) {
1227       cont = mlem->GetCellContent(j,i);
1228       if (cont < thresh) continue;
1229       if (i != i1) {i1 = i; nsumy++;}
1230       if (j != j1) {j1 = j; nsumx++;}
1231       x = mlem->GetXaxis()->GetBinCenter(j);
1232       xq += x*cont;
1233       yq += y*cont;
1234       qq += cont;
1235       nsum++;
1236     }
1237   }
1238   
1239   Double_t cmax = 0;
1240   Int_t i2 = 0, j2 = 0;
1241   x = y = 0;
1242   if (nsumy == 1) {
1243     // one bin in Y - add one more (with the largest signal)
1244     for (Int_t i = TMath::Max(1,iymax-1); i <= ie; ++i) {
1245       if (i == iymax) continue;
1246       for (Int_t j = TMath::Max(1,ixmax-1); j <= je; ++j) {
1247         cont = mlem->GetCellContent(j,i);
1248         if (cont > cmax) {
1249           cmax = cont;
1250           x = mlem->GetXaxis()->GetBinCenter(j);
1251           y = mlem->GetYaxis()->GetBinCenter(i);
1252           i2 = i;
1253           j2 = j;
1254         }
1255       }
1256     }
1257     xq += x*cmax;
1258     yq += y*cmax;
1259     qq += cmax;
1260     if (i2 != i1) nsumy++;
1261     if (j2 != j1) nsumx++;
1262     nsum++;
1263   } // if (nsumy == 1)
1264   
1265   if (nsumx == 1) {
1266     // one bin in X - add one more (with the largest signal)
1267     cmax = x = y = 0;
1268     for (Int_t j = TMath::Max(1,ixmax-1); j <= je; ++j) {
1269       if (j == ixmax) continue;
1270       for (Int_t i = TMath::Max(1,iymax-1); i <= ie; ++i) {
1271         cont = mlem->GetCellContent(j,i);
1272         if (cont > cmax) {
1273           cmax = cont;
1274           x = mlem->GetXaxis()->GetBinCenter(j);
1275           y = mlem->GetYaxis()->GetBinCenter(i);
1276           i2 = i;
1277           j2 = j;
1278         }
1279       }
1280     }
1281     xq += x*cmax;
1282     yq += y*cmax;
1283     qq += cmax;
1284     if (i2 != i1) nsumy++;
1285     if (j2 != j1) nsumx++;
1286     nsum++;
1287   } // if (nsumx == 1)
1288   
1289   xyc[0] = xq/qq; xyc[1] = yq/qq;
1290   AliDebug(2,Form("x,y COG = %e,%e",xyc[0],xyc[1]));
1291 }
1292
1293 //_____________________________________________________________________________
1294 Int_t AliMUONClusterFinderMLEM::FindNearest(AliMUONPad *pixPtr0)
1295 {
1296 /// Find the pixel nearest to the given one
1297 /// (algorithm may be not very efficient)
1298
1299   Int_t nPix = fPixArray->GetEntriesFast(), imin = 0;
1300   Double_t rmin = 99999, dx = 0, dy = 0, r = 0;
1301   Double_t xc = pixPtr0->Coord(0), yc = pixPtr0->Coord(1);
1302   AliMUONPad *pixPtr;
1303
1304   for (Int_t i = 0; i < nPix; ++i) {
1305     pixPtr = (AliMUONPad*) fPixArray->UncheckedAt(i);
1306     if (pixPtr == pixPtr0 || pixPtr->Charge() < 0.5) continue;
1307     dx = (xc - pixPtr->Coord(0)) / pixPtr->Size(0);
1308     dy = (yc - pixPtr->Coord(1)) / pixPtr->Size(1);
1309     r = dx *dx + dy * dy;
1310     if (r < rmin) { rmin = r; imin = i; }
1311   }
1312   return imin;
1313 }
1314
1315 //_____________________________________________________________________________
1316 void
1317 AliMUONClusterFinderMLEM::Paint(Option_t*)
1318 {
1319   /// Paint cluster and pixels
1320   
1321   AliMpArea area(fPreCluster->Area());
1322   
1323   gPad->Range(area.LeftBorder(),area.DownBorder(),area.RightBorder(),area.UpBorder());
1324
1325   gVirtualX->SetFillStyle(1001);
1326   gVirtualX->SetFillColor(3);    
1327   gVirtualX->SetLineColor(3);
1328   
1329   Double_t s(1.0);
1330   
1331   for ( Int_t i = 0; i <= fPixArray->GetLast(); ++i)
1332   {
1333     AliMUONPad* pixel = Pixel(i);
1334
1335     gPad->PaintBox(pixel->Coord(0)-pixel->Size(0)*s,
1336                    pixel->Coord(1)-pixel->Size(1)*s,
1337                    pixel->Coord(0)+pixel->Size(0)*s,
1338                    pixel->Coord(1)+pixel->Size(1)*s);
1339
1340 //    for ( Int_t sign = -1; sign < 2; sign +=2 )
1341 //    {
1342 //      gPad->PaintLine(pixel->Coord(0) - pixel->Size(0),
1343 //                      pixel->Coord(1) + sign*pixel->Size(1),
1344 //                      pixel->Coord(0) + pixel->Size(0),
1345 //                      pixel->Coord(1) - sign*pixel->Size(1)
1346 //                    );
1347 //    }
1348   }      
1349
1350
1351   gVirtualX->SetFillStyle(0);
1352   
1353   fPreCluster->Paint();
1354
1355   gVirtualX->SetLineColor(1);
1356   gVirtualX->SetLineWidth(2);
1357   gVirtualX->SetFillStyle(0);
1358   gVirtualX->SetTextColor(1);
1359   gVirtualX->SetTextAlign(22);
1360   
1361   for ( Int_t i = 0; i <= fPixArray->GetLast(); ++i)
1362   {
1363     AliMUONPad* pixel = Pixel(i);
1364     gPad->PaintBox(pixel->Coord(0)-pixel->Size(0),
1365                    pixel->Coord(1)-pixel->Size(1),
1366                    pixel->Coord(0)+pixel->Size(0),
1367                    pixel->Coord(1)+pixel->Size(1));    
1368     gVirtualX->SetTextSize(pixel->Size(0)*60);
1369
1370     gPad->PaintText(pixel->Coord(0),pixel->Coord(1),Form("%d",(Int_t)(pixel->Charge())));
1371   }  
1372 }
1373
1374 //_____________________________________________________________________________
1375 Int_t AliMUONClusterFinderMLEM::FindLocalMaxima(TObjArray *pixArray, Int_t *localMax, Double_t *maxVal)
1376 {
1377 /// Find local maxima in pixel space for large preclusters in order to
1378 /// try to split them into smaller pieces (to speed up the MLEM procedure)
1379 /// or to find additional fitting seeds if clusters were not completely resolved  
1380
1381   AliDebug(1,Form("nPix=%d",pixArray->GetLast()+1));
1382
1383   TH2D *hist = NULL;
1384   //if (pixArray == fPixArray) hist = (TH2D*) gROOT->FindObject("anode");
1385   //else { hist = (TH2D*) gROOT->FindObject("anode1"); cout << hist << endl; }
1386   //if (hist) hist->Delete();
1387  
1388   Double_t xylim[4] = {999, 999, 999, 999};
1389
1390   Int_t nPix = pixArray->GetEntriesFast();
1391   AliMUONPad *pixPtr = 0;
1392   for (Int_t ipix = 0; ipix < nPix; ++ipix) {
1393     pixPtr = (AliMUONPad*) pixArray->UncheckedAt(ipix);
1394     for (Int_t i = 0; i < 4; ++i) 
1395          xylim[i] = TMath::Min (xylim[i], (i%2 ? -1 : 1)*pixPtr->Coord(i/2));
1396   }
1397   for (Int_t i = 0; i < 4; ++i) xylim[i] -= pixPtr->Size(i/2); 
1398
1399   Int_t nx = TMath::Nint ((-xylim[1]-xylim[0])/pixPtr->Size(0)/2);
1400   Int_t ny = TMath::Nint ((-xylim[3]-xylim[2])/pixPtr->Size(1)/2);
1401   if (pixArray == fPixArray) hist = new TH2D("anode","anode",nx,xylim[0],-xylim[1],ny,xylim[2],-xylim[3]);
1402   else hist = new TH2D("anode1","anode1",nx,xylim[0],-xylim[1],ny,xylim[2],-xylim[3]);
1403   for (Int_t ipix = 0; ipix < nPix; ++ipix) {
1404     pixPtr = (AliMUONPad*) pixArray->UncheckedAt(ipix);
1405     hist->Fill(pixPtr->Coord(0), pixPtr->Coord(1), pixPtr->Charge());
1406   }
1407 //  if (fDraw && pixArray == fPixArray) fDraw->DrawHist("c2", hist);
1408
1409   Int_t nMax = 0, indx, nxy = ny * nx;
1410   Int_t *isLocalMax = new Int_t[nxy];
1411   for (Int_t i = 0; i < nxy; ++i) isLocalMax[i] = 0; 
1412
1413   for (Int_t i = 1; i <= ny; ++i) {
1414     indx = (i-1) * nx;
1415     for (Int_t j = 1; j <= nx; ++j) {
1416       if (hist->GetCellContent(j,i) < 0.5) continue;
1417       //if (isLocalMax[indx+j-1] < 0) continue;
1418       if (isLocalMax[indx+j-1] != 0) continue;
1419       FlagLocalMax(hist, i, j, isLocalMax);
1420     }
1421   }
1422
1423   for (Int_t i = 1; i <= ny; ++i) {
1424     indx = (i-1) * nx;
1425     for (Int_t j = 1; j <= nx; ++j) {
1426       if (isLocalMax[indx+j-1] > 0) { 
1427         localMax[nMax] = indx + j - 1; 
1428         maxVal[nMax++] = hist->GetCellContent(j,i);
1429         ((AliMUONPad*)fSplitter->BinToPix(hist, j, i))->SetStatus(fgkMustKeep);
1430         if (nMax > 99) AliFatal(" Too many local maxima !!!");
1431       }
1432     }
1433   }
1434   if (fDebug) cout << " Local max: " << nMax << endl;
1435   delete [] isLocalMax; 
1436   return nMax;
1437 }
1438
1439 //_____________________________________________________________________________
1440 void AliMUONClusterFinderMLEM::FlagLocalMax(TH2D *hist, Int_t i, Int_t j, Int_t *isLocalMax)
1441 {
1442 /// Flag pixels (whether or not local maxima)
1443
1444   Int_t nx = hist->GetNbinsX();
1445   Int_t ny = hist->GetNbinsY();
1446   Int_t cont = TMath::Nint (hist->GetCellContent(j,i));
1447   Int_t cont1 = 0, indx = (i-1)*nx+j-1, indx1 = 0, indx2 = 0;
1448
1449   Int_t ie = i + 2, je = j + 2;
1450   for (Int_t i1 = i-1; i1 < ie; ++i1) {
1451     if (i1 < 1 || i1 > ny) continue;
1452     indx1 = (i1 - 1) * nx;
1453     for (Int_t j1 = j-1; j1 < je; ++j1) {
1454       if (j1 < 1 || j1 > nx) continue;
1455       if (i == i1 && j == j1) continue;
1456       indx2 = indx1 + j1 - 1;
1457       cont1 = TMath::Nint (hist->GetCellContent(j1,i1));
1458       if (cont < cont1) { isLocalMax[indx] = -1; return; }
1459       else if (cont > cont1) isLocalMax[indx2] = -1;
1460       else { // the same charge
1461         isLocalMax[indx] = 1; 
1462         if (isLocalMax[indx2] == 0) {
1463           FlagLocalMax(hist, i1, j1, isLocalMax);
1464           if (isLocalMax[indx2] < 0) { isLocalMax[indx] = -1; return; }
1465           else isLocalMax[indx2] = -1;
1466         }
1467       } 
1468     }
1469   }
1470   isLocalMax[indx] = 1; // local maximum
1471 }
1472
1473 //_____________________________________________________________________________
1474 void AliMUONClusterFinderMLEM::FindCluster(AliMUONCluster& cluster, 
1475                                            Int_t *localMax, Int_t iMax)
1476 {
1477 /// Find pixel cluster around local maximum \a iMax and pick up pads
1478 /// overlapping with it
1479
1480   TH2D *hist = (TH2D*) gROOT->FindObject("anode");
1481   /* Just for check
1482   TCanvas* c = new TCanvas("Anode","Anode",800,600);
1483   c->cd();
1484   hist->Draw("lego1Fb"); // debug
1485   c->Update();
1486   Int_t tmp;
1487   cin >> tmp;
1488   */
1489   Int_t nx = hist->GetNbinsX();
1490   Int_t ny = hist->GetNbinsY();
1491   Int_t ic = localMax[iMax] / nx + 1;
1492   Int_t jc = localMax[iMax] % nx + 1;
1493   Int_t nxy = ny * nx;
1494   Bool_t *used = new Bool_t[nxy];
1495   for (Int_t i = 0; i < nxy; ++i) used[i] = kFALSE; 
1496
1497   // Drop all pixels from the array - pick up only the ones from the cluster
1498   fPixArray->Delete();
1499
1500   Double_t wx = hist->GetXaxis()->GetBinWidth(1)/2; 
1501   Double_t wy = hist->GetYaxis()->GetBinWidth(1)/2;  
1502   Double_t yc = hist->GetYaxis()->GetBinCenter(ic);
1503   Double_t xc = hist->GetXaxis()->GetBinCenter(jc);
1504   Double_t cont = hist->GetCellContent(jc,ic);
1505   fPixArray->Add(new AliMUONPad (xc, yc, wx, wy, cont));
1506   used[(ic-1)*nx+jc-1] = kTRUE;
1507   AddBinSimple(hist, ic, jc);
1508   //fSplitter->AddBin(hist, ic, jc, 1, used, (TObjArray*)0); // recursive call
1509
1510   Int_t nPix = fPixArray->GetEntriesFast();
1511   Int_t npad = cluster.Multiplicity();
1512   
1513   for (Int_t i = 0; i < nPix; ++i) 
1514   {
1515     AliMUONPad* pixPtr = Pixel(i);
1516     pixPtr->SetSize(0,wx);
1517     pixPtr->SetSize(1,wy);
1518   }
1519
1520   // Pick up pads which overlap with found pixels
1521   for (Int_t i = 0; i < npad; ++i) 
1522   {
1523     //cluster.Pad(i)->SetStatus(-1);
1524     cluster.Pad(i)->SetStatus(fgkOver); // just the dirty trick
1525   }
1526   
1527   for (Int_t i = 0; i < nPix; ++i) 
1528   {
1529     AliMUONPad* pixPtr = Pixel(i);
1530     for (Int_t j = 0; j < npad; ++j) 
1531     {
1532       AliMUONPad* pad = cluster.Pad(j);
1533       //if (pad->Status() == 0) continue;
1534       if (pad->Status() == fgkZero) continue;
1535       if ( Overlap(*pad,*pixPtr) )
1536       {
1537         //pad->SetStatus(0);
1538         pad->SetStatus(fgkZero);
1539         if (fDebug) { cout << j << " "; pad->Print("full"); }
1540       }
1541     }
1542   }
1543
1544   delete [] used;
1545 }
1546
1547 //_____________________________________________________________________________
1548 void 
1549 AliMUONClusterFinderMLEM::AddBinSimple(TH2D *mlem, Int_t ic, Int_t jc)
1550 {
1551   /// Add adjacent bins (+-1 in X and Y) to the cluster
1552   
1553   Int_t nx = mlem->GetNbinsX();
1554   Int_t ny = mlem->GetNbinsY();
1555   Double_t cont1, cont = mlem->GetCellContent(jc,ic);
1556   AliMUONPad *pixPtr = 0;
1557   
1558   Int_t ie = TMath::Min(ic+1,ny), je = TMath::Min(jc+1,nx);
1559   for (Int_t i = TMath::Max(ic-1,1); i <= ie; ++i) {
1560     for (Int_t j = TMath::Max(jc-1,1); j <= je; ++j) {
1561       cont1 = mlem->GetCellContent(j,i);
1562       if (cont1 > cont) continue;
1563       if (cont1 < 0.5) continue;
1564       pixPtr = new AliMUONPad (mlem->GetXaxis()->GetBinCenter(j), 
1565                                mlem->GetYaxis()->GetBinCenter(i), 0, 0, cont1);
1566       fPixArray->Add(pixPtr);
1567     }
1568   }
1569 }
1570
1571 //_____________________________________________________________________________
1572 AliMUONClusterFinderMLEM&  
1573 AliMUONClusterFinderMLEM::operator=(const AliMUONClusterFinderMLEM& rhs)
1574 {
1575 /// Protected assignement operator
1576
1577   if (this == &rhs) return *this;
1578
1579   AliFatal("Not implemented.");
1580     
1581   return *this;  
1582 }    
1583
1584 //_____________________________________________________________________________
1585 void AliMUONClusterFinderMLEM::AddVirtualPad(AliMUONCluster& cluster)
1586 {
1587   /// Add virtual pad (with small charge) to improve fit for clusters
1588   /// with number of pads == 2 per direction
1589   
1590   // Find out non-bending and bending planes
1591   Int_t nonb[2] = {1, 0}; // non-bending and bending cathodes
1592
1593   TVector2 dim0 = cluster.MinPadDimensions(0, 0, kTRUE);
1594   TVector2 dim1 = cluster.MinPadDimensions(1, 0, kTRUE);
1595   if (dim0.X() < dim1.X() - fgkDistancePrecision) {
1596     nonb[0] = 0;
1597     nonb[1] = 1;
1598   } 
1599
1600   Bool_t same = kFALSE;
1601   if (TMath::Abs(dim0.Y()-dim1.Y()) < fgkDistancePrecision) same = kTRUE; // the same pad size on both planes 
1602
1603   AliMpIntPair cn;
1604   Bool_t check[2] = {kFALSE, kFALSE};
1605   Int_t nxy[2];
1606   nxy[0] = nxy[1] = 0;
1607   for (Int_t inb = 0; inb < 2; ++inb) {
1608     cn = cluster.NofPads(nonb[inb], 0, kTRUE);
1609     if (inb == 0 && cn.GetFirst() == 2) check[inb] = kTRUE; // check non-bending plane
1610     else if (inb == 1 && cn.GetSecond() == 2) check[inb] = kTRUE; // check bending plane
1611     if (same) {
1612       nxy[0] = TMath::Max (nxy[0], cn.GetFirst());
1613       nxy[1] = TMath::Max (nxy[1], cn.GetSecond());
1614       if (inb == 0 && nxy[0] < 2) nonb[inb] = !nonb[inb];
1615       else if (inb == 1 && cn.GetSecond() < 2) nonb[inb] = !nonb[inb];
1616     }
1617   }
1618   if (same) {
1619     if (nxy[0] > 2) check[0] = kFALSE;
1620     if (nxy[1] > 2) check[1] = kFALSE;
1621   }
1622   if (!check[0] && !check[1]) return;
1623
1624   for (Int_t inb = 0; inb < 2; ++inb) {
1625     if (!check[inb]) continue;
1626
1627     // Find pads with maximum and next to maximum charges 
1628     Int_t maxPads[2] = {-1, -1};
1629     Double_t amax[2] = {0};
1630     Int_t mult = cluster.Multiplicity();
1631     for (Int_t j = 0; j < mult; ++j) {
1632       AliMUONPad *pad = cluster.Pad(j);
1633       if (pad->Cathode() != nonb[inb]) continue;
1634       for (Int_t j2 = 0; j2 < 2; ++j2) {
1635         if (pad->Charge() > amax[j2]) {
1636           if (j2 == 0) { amax[1] = amax[0]; maxPads[1] = maxPads[0]; }
1637           amax[j2] = pad->Charge();
1638           maxPads[j2] = j;
1639           break;
1640         }
1641       }
1642     }
1643
1644     // Find min and max dimensions of the cluster
1645     Double_t limits[2] = {9999, -9999};
1646     for (Int_t j = 0; j < mult; ++j) {
1647       AliMUONPad *pad = cluster.Pad(j);
1648       if (pad->Cathode() != nonb[inb]) continue;
1649       if (pad->Coord(inb) < limits[0]) limits[0] = pad->Coord(inb);
1650       if (pad->Coord(inb) > limits[1]) limits[1] = pad->Coord(inb);
1651     }
1652
1653     // Loop over max and next to max pads
1654     Bool_t add = kFALSE;
1655     Int_t idirAdd = 0;
1656     for (Int_t j = 0; j < 2; ++j) {
1657       if (j == 1) {
1658         if (maxPads[j] < 0) continue;
1659         if (!add) break; 
1660         if (amax[1] / amax[0] < 0.5) break;
1661       }
1662       // Check if pad at the cluster limit
1663       AliMUONPad *pad = cluster.Pad(maxPads[j]);
1664       Int_t idir = 0;
1665       if (TMath::Abs(pad->Coord(inb)-limits[0]) < fgkDistancePrecision) idir = -1;
1666       else if (TMath::Abs(pad->Coord(inb)-limits[1]) < fgkDistancePrecision) idir = 1;
1667       else {
1668         //cout << " *** Pad not at the cluster limit: " << j << endl;
1669         break;
1670       }
1671       if (j == 1 && idir == idirAdd) break; // this pad has been already added
1672
1673       // Add pad (if it exists)
1674       TVector2 pos;
1675       if (inb == 0) pos.Set (pad->X() + idir * (pad->DX()+fgkDistancePrecision), pad->Y());
1676       else pos.Set (pad->X(), pad->Y() + idir * (pad->DY()+fgkDistancePrecision));
1677       //AliMpPad mppad = fSegmentation[nonb[inb]]->PadByPosition(pos,kTRUE);
1678       AliMpPad mppad = fSegmentation[nonb[inb]]->PadByPosition(pos,kFALSE);
1679       if (!mppad.IsValid()) continue; // non-existing pad
1680       cn = mppad.GetIndices();
1681       AliMUONPad muonPad(fDetElemId, nonb[inb], cn.GetFirst(), cn.GetSecond(), 
1682                          mppad.Position().X(), mppad.Position().Y(), 
1683                          mppad.Dimensions().X(), mppad.Dimensions().Y(), 0);
1684       if (inb == 0) muonPad.SetCharge(TMath::Min (amax[j]/100, 5.));
1685       //else muonPad.SetCharge(TMath::Min (amax[j]/15, fgkZeroSuppression));
1686       else muonPad.SetCharge(TMath::Min (amax[j]/15, 6.));
1687       if (muonPad.Charge() < 1.) muonPad.SetCharge(1.);
1688       muonPad.SetReal(kFALSE);
1689       if (fDebug) printf(" ***** Add virtual pad in %d direction ***** %f %f %f %3d %3d %f %f \n",
1690                          inb, muonPad.Charge(), muonPad.X(), muonPad.Y(), muonPad.Ix(), 
1691                          muonPad.Iy(), muonPad.DX(), muonPad.DY());
1692       cluster.AddPad(muonPad); // add pad to the cluster
1693       add = kTRUE;
1694       idirAdd = idir;
1695     }
1696   }
1697 }
1698
1699 //_____________________________________________________________________________
1700 void AliMUONClusterFinderMLEM::PadsInXandY(AliMUONCluster& cluster,
1701                                            Int_t &nInX, Int_t &nInY) const
1702 {
1703   /// Find number of pads in X and Y-directions (excluding virtual ones and
1704   /// overflows)
1705
1706   //Int_t statusToTest = 1;
1707   Int_t statusToTest = fgkUseForFit;
1708   
1709   //if ( nInX < 0 ) statusToTest = 0;
1710   if ( nInX < 0 ) statusToTest = fgkZero;
1711        
1712   Bool_t mustMatch(kTRUE);
1713
1714   AliMpIntPair cn = cluster.NofPads(statusToTest,mustMatch);
1715   
1716   nInX = cn.GetFirst();
1717   nInY = cn.GetSecond();
1718 }
1719
1720 //_____________________________________________________________________________
1721 void AliMUONClusterFinderMLEM::RemovePixel(Int_t i)
1722 {
1723   /// Remove pixel at index i
1724   AliMUONPad* pixPtr = Pixel(i);
1725   fPixArray->RemoveAt(i); 
1726   delete pixPtr;
1727 }
1728
1729 //_____________________________________________________________________________
1730 void AliMUONClusterFinderMLEM::Simple(AliMUONCluster& cluster)
1731 {
1732 /// Process simple cluster (small number of pads) without EM-procedure
1733
1734   Int_t nForFit = 1, clustFit[1] = {0}, nfit;
1735   Double_t parOk[3] = {0.}; 
1736   TObjArray *clusters[1]; 
1737   clusters[0] = fPixArray;
1738
1739   AliDebug(1,Form("nPix=%d",fPixArray->GetLast()+1));
1740
1741   Int_t mult = cluster.Multiplicity();
1742   for (Int_t i = 0; i < mult; ++i) 
1743   {
1744     AliMUONPad* pad = cluster.Pad(i);
1745     /*
1746     if ( pad->IsSaturated()) 
1747     {
1748       pad->SetStatus(-9);
1749     }
1750     else 
1751     {
1752       pad->SetStatus(1);
1753     }
1754     */
1755     if (!pad->IsSaturated()) pad->SetStatus(fgkUseForFit);
1756   }
1757   nfit = fSplitter->Fit(cluster,1, nForFit, clustFit, clusters, parOk, fClusterList);
1758 }
1759
1760 //_____________________________________________________________________________
1761 AliMUONPad* 
1762 AliMUONClusterFinderMLEM::Pixel(Int_t i) const
1763 {
1764   /// Returns pixel at index i
1765   return static_cast<AliMUONPad*>(fPixArray->UncheckedAt(i));
1766 }
1767
1768 //_____________________________________________________________________________
1769 void 
1770 AliMUONClusterFinderMLEM::Print(Option_t* what) const
1771 {
1772   /// printout
1773   TString swhat(what);
1774   swhat.ToLower();
1775   if ( swhat.Contains("precluster") )
1776   {
1777     if ( fPreCluster) fPreCluster->Print();
1778   }
1779 }
1780
1781