LCOV - code coverage report
Current view: top level - MUON/MUONrec - AliMUONClusterFinderPeakFit.cxx (source / functions) Hit Total Coverage
Test: coverage.info Lines: 3 586 0.5 %
Date: 2016-06-14 17:26:59 Functions: 3 29 10.3 %

          Line data    Source code
       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 AliMUONClusterFinderPeakFit
      20             : /// 
      21             : /// Clusterizer class based on simple peak finder
      22             : ///
      23             : /// Pre-clustering is handled by AliMUONPreClusterFinder
      24             : /// From a precluster a pixel array is built, and its local maxima are used
      25             : /// to get pads and make the fit with up to 3 hit candidates or compute pad 
      26             : /// centers of gravity for larger number of peaks.
      27             : ///
      28             : /// \author Laurent Aphecetche (for the "new" C++ structure) and 
      29             : /// Alexander Zinchenko, JINR Dubna, for the hardcore of it ;-)
      30             : //-----------------------------------------------------------------------------
      31             : 
      32             : #include "AliMUONClusterFinderPeakFit.h"
      33             : #include "AliMUONCluster.h"
      34             : #include "AliMUONConstants.h"
      35             : #include "AliMUONPad.h"
      36             : #include "AliMUONMathieson.h"
      37             : 
      38             : #include "AliMpDEManager.h"
      39             : #include "AliMpPad.h"
      40             : #include "AliMpVSegmentation.h"
      41             : #include "AliMpEncodePair.h"
      42             : 
      43             : #include "AliLog.h"
      44             : #include "AliRunLoader.h"
      45             : //#include "AliCodeTimer.h"
      46             : 
      47             : #include <Riostream.h>
      48             : #include <TH2.h>
      49             : #include <TVirtualFitter.h>
      50             : #include <TMath.h>
      51             : //#include <TCanvas.h>
      52             : 
      53             : using std::endl;
      54             : using std::cout;
      55             : /// \cond CLASSIMP
      56          18 : ClassImp(AliMUONClusterFinderPeakFit)
      57             : /// \endcond
      58             :  
      59             : const Double_t AliMUONClusterFinderPeakFit::fgkZeroSuppression = 6; // average zero suppression value
      60             : //const Double_t AliMUONClusterFinderMLEM::fgkDistancePrecision = 1e-6; // (cm) used to check overlaps and so on
      61             : const Double_t AliMUONClusterFinderPeakFit::fgkDistancePrecision = 1e-3; // (cm) used to check overlaps and so on
      62          18 : const TVector2 AliMUONClusterFinderPeakFit::fgkIncreaseSize(-AliMUONClusterFinderPeakFit::fgkDistancePrecision,-AliMUONClusterFinderPeakFit::fgkDistancePrecision);
      63          18 : const TVector2 AliMUONClusterFinderPeakFit::fgkDecreaseSize(AliMUONClusterFinderPeakFit::fgkDistancePrecision,AliMUONClusterFinderPeakFit::fgkDistancePrecision);
      64             : 
      65             : // Status flags for pads
      66             : const Int_t AliMUONClusterFinderPeakFit::fgkZero = 0x0; ///< pad "basic" state
      67             : const Int_t AliMUONClusterFinderPeakFit::fgkMustKeep = 0x1; ///< do not kill (for pixels)
      68             : const Int_t AliMUONClusterFinderPeakFit::fgkUseForFit = 0x10; ///< should be used for fit
      69             : const Int_t AliMUONClusterFinderPeakFit::fgkOver = 0x100; ///< processing is over
      70             : const Int_t AliMUONClusterFinderPeakFit::fgkModified = 0x1000; ///< modified pad charge 
      71             : const Int_t AliMUONClusterFinderPeakFit::fgkCoupled = 0x10000; ///< coupled pad  
      72             : 
      73             : namespace
      74             : {
      75             :   //_____________________________________________________________________________
      76             :   Double_t Param2Coef(Int_t icand, Double_t coef, Double_t *par, Int_t nHits)
      77             :   {
      78             :     /// Extract hit contribution scale factor from fit parameters
      79             :   
      80             :     //Int_t nHits = TMath::Nint(par[8]);
      81           0 :     if (nHits == 1) return 1.;
      82           0 :     if (nHits == 2) return icand==0 ? par[2] : TMath::Max(1.-par[2],0.);
      83           0 :     if (icand == 0) return par[2];
      84           0 :     if (icand == 1) return TMath::Max((1.-par[2])*par[5], 0.);
      85           0 :     return TMath::Max(1.-par[2]-coef,0.);
      86           0 :   }
      87             : 
      88             :   //___________________________________________________________________________
      89             :   void 
      90             :   FitFunction(Int_t& /*notused*/, Double_t* /*notused*/, 
      91             :               Double_t& f, Double_t* par, 
      92             :               Int_t /*notused*/)
      93             :   {
      94             :     /// Chi2 Function to minimize: Mathieson charge distribution in 2 dimensions
      95             :     
      96           0 :     TObjArray* userObjects = static_cast<TObjArray*>(TVirtualFitter::GetFitter()->GetObjectFit());
      97             :     
      98           0 :     AliMUONCluster* cluster = static_cast<AliMUONCluster*>(userObjects->At(0));
      99           0 :     AliMUONMathieson* mathieson = static_cast<AliMUONMathieson*>(userObjects->At(1));
     100             :     AliMUONClusterFinderPeakFit* finder = 
     101           0 :       static_cast<AliMUONClusterFinderPeakFit*>(userObjects->At(2));
     102             :     
     103           0 :     f = 0.0;
     104           0 :     Int_t nHits = finder->GetNMax(), npads = cluster->Multiplicity();
     105           0 :     Double_t qTot = cluster->Charge(), coef = 0;
     106             :     //if (cluster->Multiplicity(0) == 0 || cluster->Multiplicity(1) == 0) qTot *= 2.;
     107             :     
     108           0 :     for ( Int_t i = 0 ; i < npads; ++i )
     109             :     {
     110           0 :       AliMUONPad* pad = cluster->Pad(i);
     111             :       // skip pads w/ saturation or other problem(s)
     112             :       //if ( pad->Status() ) continue; 
     113           0 :       if ( pad->IsSaturated() ) continue; 
     114             :       Double_t charge = 0.;
     115           0 :       for (Int_t j = 0; j < nHits; ++j) {
     116             :         // Sum over hits
     117           0 :         Int_t indx = 3 * j;
     118           0 :         TVector2 lowerLeft = TVector2(par[indx],par[indx+1]) - pad->Position() - pad->Dimensions();
     119           0 :         TVector2 upperRight(lowerLeft + pad->Dimensions()*2.0);
     120           0 :         Double_t estimatedCharge = mathieson->IntXY(lowerLeft.X(),lowerLeft.Y(),
     121           0 :                                                     upperRight.X(),upperRight.Y());
     122           0 :         coef = Param2Coef(j, coef, par, nHits);
     123           0 :         charge += estimatedCharge * coef;
     124           0 :       }
     125           0 :       charge *= qTot;
     126             :       
     127           0 :       Double_t delta = charge - pad->Charge();
     128           0 :       delta *= delta;
     129           0 :       delta /= pad->Charge();    
     130           0 :       f += delta;
     131           0 :     }
     132           0 :     f /= (qTot/npads);
     133             :     //cout << qTot << " " << par[0] << " " << par[1] << " " << f << endl;
     134           0 :   }
     135             : }
     136             : 
     137             : //_____________________________________________________________________________
     138             : AliMUONClusterFinderPeakFit::AliMUONClusterFinderPeakFit(Bool_t plot, AliMUONVClusterFinder* clusterFinder)
     139           0 :   : AliMUONVClusterFinder(),
     140           0 : fPreClusterFinder(clusterFinder),
     141           0 : fPreCluster(0x0),
     142           0 : fClusterList(),
     143           0 : fMathieson(0x0),
     144           0 : fEventNumber(0),
     145           0 : fDetElemId(-1),
     146           0 : fClusterNumber(0),
     147           0 : fNMax(0),
     148           0 : fHistAnode(0x0),
     149           0 : fPixArray(new TObjArray(20)),
     150           0 : fDebug(0),
     151           0 : fPlot(plot),
     152           0 : fNClusters(0),
     153           0 : fNAddVirtualPads(0)
     154           0 : {
     155             :   /// Constructor
     156             :  
     157           0 :   fkSegmentation[1] = fkSegmentation[0] = 0x0; 
     158             : 
     159           0 :   if (fPlot) fDebug = 1;
     160           0 : }
     161             : 
     162             : //_____________________________________________________________________________
     163             : AliMUONClusterFinderPeakFit::~AliMUONClusterFinderPeakFit()
     164           0 : {
     165             : /// Destructor
     166           0 :   delete fPixArray; fPixArray = 0;
     167           0 :   delete fPreClusterFinder;
     168           0 :   AliInfo(Form("Total clusters %d AddVirtualPad needed %d",
     169             :                fNClusters,fNAddVirtualPads));
     170           0 :   delete fMathieson;
     171           0 : }
     172             : 
     173             : //_____________________________________________________________________________
     174             : Bool_t 
     175             : AliMUONClusterFinderPeakFit::Prepare(Int_t detElemId, TObjArray* pads[2],
     176             :                                      const AliMpArea& area, 
     177             :                                      const AliMpVSegmentation* seg[2])
     178             : {
     179             :   /// Prepare for clustering
     180             : //  AliCodeTimerAuto("",0)
     181             :   
     182           0 :   for ( Int_t i = 0; i < 2; ++i )
     183             :   {
     184           0 :     fkSegmentation[i] = seg[i];
     185             :   }
     186             :   
     187             :   // Find out the DetElemId
     188           0 :   fDetElemId = detElemId;
     189             :   
     190             :   // find out current event number, and reset the cluster number
     191           0 :   AliRunLoader *runLoader = AliRunLoader::Instance();
     192           0 :   fEventNumber = runLoader ? runLoader->GetEventNumber() : 0;
     193           0 :   fClusterNumber = -1;
     194           0 :   fClusterList.Delete();
     195             :   
     196           0 :   AliDebug(3,Form("EVT %d DE %d",fEventNumber,fDetElemId));
     197             :   
     198           0 :   AliMq::Station12Type stationType = AliMpDEManager::GetStation12Type(fDetElemId);
     199             :   
     200           0 :   Float_t kx3 = AliMUONConstants::SqrtKx3();
     201           0 :   Float_t ky3 = AliMUONConstants::SqrtKy3();
     202           0 :   Float_t pitch = AliMUONConstants::Pitch();
     203             :   
     204           0 :   if ( stationType == AliMq::kStation1 )
     205             :   {
     206           0 :     kx3 = AliMUONConstants::SqrtKx3St1();
     207           0 :     ky3 = AliMUONConstants::SqrtKy3St1();
     208           0 :     pitch = AliMUONConstants::PitchSt1();
     209           0 :   }
     210             :   
     211           0 :   delete fMathieson;
     212           0 :   fMathieson = new AliMUONMathieson;
     213             :   
     214           0 :   fMathieson->SetPitch(pitch);
     215           0 :   fMathieson->SetSqrtKx3AndDeriveKx2Kx4(kx3);
     216           0 :   fMathieson->SetSqrtKy3AndDeriveKy2Ky4(ky3);
     217             : 
     218           0 :   if ( fPreClusterFinder->NeedSegmentation() )
     219             :   {
     220           0 :     return fPreClusterFinder->Prepare(detElemId,pads,area,seg);
     221             :   }
     222             :   else
     223             :   {
     224           0 :     return fPreClusterFinder->Prepare(detElemId,pads,area);
     225             :   }
     226           0 : }
     227             : 
     228             : //_____________________________________________________________________________
     229             : AliMUONCluster* 
     230             : AliMUONClusterFinderPeakFit::NextCluster()
     231             : {
     232             :   /// Return next cluster
     233             : //  AliCodeTimerAuto("",0)
     234             :   
     235             :   // if the list of clusters is not void, pick one from there
     236           0 :   TObject* o = fClusterList.At(++fClusterNumber);
     237           0 :   if ( o != 0x0 ) return static_cast<AliMUONCluster*>(o);
     238             :   
     239             :   //FIXME : at this point, must check whether we've used all the digits
     240             :   //from precluster : if not, let the preclustering know about those unused
     241             :   //digits, so it can reuse them
     242             :   
     243             :   // if the cluster list is exhausted, we need to go to the next
     244             :   // pre-cluster and treat it
     245             : 
     246           0 :   fClusterList.Delete(); // reset the list of clusters for this pre-cluster
     247           0 :   fClusterNumber = -1; 
     248             :     
     249           0 :   fPreCluster = fPreClusterFinder->NextCluster();
     250             :   
     251           0 :   if (!fPreCluster)
     252             :   {
     253             :     // we are done
     254           0 :     return 0x0;
     255             :   }
     256             :     
     257           0 :   WorkOnPreCluster();
     258             : 
     259             :   // WorkOnPreCluster may have used only part of the pads, so we check that
     260             :   // now, and let the unused pads be reused by the preclustering...
     261             :   
     262           0 :   Int_t mult = fPreCluster->Multiplicity();
     263           0 :   for ( Int_t i = 0; i < mult; ++i )
     264             :   {
     265           0 :     AliMUONPad* pad = fPreCluster->Pad(i);
     266           0 :     if ( !pad->IsUsed() )
     267             :     {
     268           0 :       fPreClusterFinder->UsePad(*pad);
     269           0 :     }
     270             :   }
     271             :   
     272           0 :   return NextCluster();
     273           0 : }
     274             : 
     275             : //_____________________________________________________________________________
     276             : Bool_t
     277             : AliMUONClusterFinderPeakFit::WorkOnPreCluster()
     278             : {
     279             :   /// Starting from a precluster, builds a pixel array, and then
     280             :   /// extract clusters from this array
     281             :   
     282             :   //  AliCodeTimerAuto("",0)  
     283             : 
     284           0 :   if (fDebug) {
     285           0 :     cout << " *** Event # " << fEventNumber
     286           0 :          << " det. elem.: " << fDetElemId << endl;
     287           0 :     for (Int_t j = 0; j < fPreCluster->Multiplicity(); ++j) {
     288           0 :       AliMUONPad* pad = fPreCluster->Pad(j);
     289           0 :       printf(" bbb %3d %1d %8.4f %8.4f %8.4f %8.4f %6.1f %3d %3d %2d %1d %1d \n",
     290           0 :              j, pad->Cathode(), pad->Coord(0), pad->Coord(1), pad->DX()*2, pad->DY()*2,
     291           0 :              pad->Charge(), pad->Ix(), pad->Iy(), pad->Status(), pad->IsReal(), pad->IsSaturated());
     292             :     }
     293           0 :   }
     294             : 
     295           0 :   AliMUONCluster* cluster = CheckPrecluster(*fPreCluster);
     296           0 :   if (!cluster) return kFALSE;
     297             : 
     298           0 :   BuildPixArray(*cluster);
     299             :   
     300           0 :   if ( fPixArray->GetLast() < 0 )
     301             :   {
     302           0 :     AliDebug(1,"No pixel for the above cluster");
     303           0 :     delete cluster;
     304           0 :     return kFALSE;
     305             :   }
     306             :   
     307           0 :   Int_t nMax = 1, localMax[100], maxPos[100] = {0};
     308           0 :   Double_t maxVal[100];
     309             :   
     310           0 :   nMax = FindLocalMaxima(fPixArray, localMax, maxVal); // find local maxima
     311             : 
     312           0 :   if (nMax > 1) TMath::Sort(nMax, maxVal, maxPos, kTRUE); // in descending order
     313             :   
     314           0 :   if (nMax <= 3) {
     315           0 :     FindClusterFit(*cluster, localMax, maxPos, nMax);
     316           0 :   } else {
     317           0 :     for (Int_t i = 0; i < nMax; ++i) 
     318             :       {
     319           0 :         FindClusterCOG(*cluster, localMax, maxPos[i]);
     320             :       }
     321             :   }
     322             : 
     323           0 :   delete cluster;
     324           0 :   if (fPlot == 0) {
     325           0 :     delete fHistAnode;
     326           0 :     fHistAnode = 0x0;
     327           0 :   }
     328             :   return kTRUE;
     329           0 : }
     330             : 
     331             : //_____________________________________________________________________________
     332             : Bool_t 
     333             : AliMUONClusterFinderPeakFit::Overlap(const AliMUONPad& pad, const AliMUONPad& pixel)
     334             : {
     335             :   /// Check if the pad and the pixel overlaps
     336             : 
     337             :   // make a fake pad from the pixel
     338           0 :   AliMUONPad tmp(pad.DetElemId(),pad.Cathode(),pad.Ix(),pad.Iy(),
     339           0 :                  pixel.Coord(0),pixel.Coord(1),
     340           0 :                  pixel.Size(0),pixel.Size(1),0);
     341             :   
     342           0 :   return AliMUONPad::AreOverlapping(pad,tmp,fgkDecreaseSize);
     343           0 : }
     344             : 
     345             : //_____________________________________________________________________________
     346             : AliMUONCluster* 
     347             : AliMUONClusterFinderPeakFit::CheckPrecluster(const AliMUONCluster& origCluster)
     348             : {
     349             :   /// Check precluster in order to attempt to simplify it (mostly for
     350             :   /// two-cathode preclusters)
     351             :     
     352             :   //  AliCodeTimerAuto("",0)
     353             : 
     354             :   // Disregard small clusters (leftovers from splitting or noise)
     355           0 :   if ((origCluster.Multiplicity()==1 || origCluster.Multiplicity()==2) &&
     356           0 :       origCluster.Charge(0)+origCluster.Charge(1) < 1.525) // JC: adc -> fc
     357             :   { 
     358           0 :     return 0x0;
     359             :   }
     360             : 
     361           0 :   AliMUONCluster* cluster = new AliMUONCluster(origCluster);
     362             : 
     363           0 :   AliDebug(2,"Start of CheckPreCluster=");
     364             :   //StdoutToAliDebug(2,cluster->Print("full"));
     365             : 
     366             :   AliMUONCluster* rv(0x0);
     367             :   
     368           0 :   if (cluster->Multiplicity(0) && cluster->Multiplicity(1))
     369             :   { 
     370           0 :     rv = CheckPreclusterTwoCathodes(cluster);
     371           0 :   }
     372             :   else
     373             :   {
     374             :     rv = cluster;
     375             :   }
     376             :   return rv;
     377           0 : }
     378             : 
     379             : //_____________________________________________________________________________
     380             : AliMUONCluster*
     381             : AliMUONClusterFinderPeakFit::CheckPreclusterTwoCathodes(AliMUONCluster* cluster)
     382             : {
     383             :   /// Check two-cathode cluster
     384             :   
     385           0 :   Int_t npad = cluster->Multiplicity();
     386           0 :   Int_t* flags = new Int_t[npad];
     387           0 :   for (Int_t j = 0; j < npad; ++j) flags[j] = 0;
     388             :   
     389             :   // Check pad overlaps
     390           0 :   for ( Int_t i = 0; i < npad; ++i) 
     391             :   {
     392           0 :     AliMUONPad* padi = cluster->Pad(i);
     393           0 :     if ( padi->Cathode() != 0 ) continue;
     394           0 :     for (Int_t j = i+1; j < npad; ++j) 
     395             :     {
     396           0 :       AliMUONPad* padj = cluster->Pad(j);
     397           0 :       if ( padj->Cathode() != 1 ) continue;
     398           0 :       if ( !AliMUONPad::AreOverlapping(*padi,*padj,fgkDecreaseSize) ) continue;
     399           0 :       flags[i] = flags[j] = 1; // mark overlapped pads
     400           0 :     } 
     401           0 :   } 
     402             :   
     403             :   // Check if all pads overlap
     404             :   Int_t nFlags=0;
     405           0 :   for (Int_t i = 0; i < npad; ++i) 
     406             :   {
     407           0 :     if (!flags[i]) ++nFlags;
     408             :   }
     409             :   
     410           0 :   if (nFlags > 0) 
     411             :   {
     412             :     // not all pads overlap.
     413           0 :     if (fDebug) cout << " nFlags: " << nFlags << endl;
     414           0 :     TObjArray toBeRemoved;
     415           0 :     for (Int_t i = 0; i < npad; ++i) 
     416             :     {
     417           0 :       AliMUONPad* pad = cluster->Pad(i);
     418           0 :       if (flags[i]) continue;
     419           0 :       Int_t cath = pad->Cathode();
     420           0 :       Int_t cath1 = TMath::Even(cath);
     421             :       // Check for edge effect (missing pads on the _other_ cathode)
     422           0 :       AliMpPad mpPad 
     423           0 :         = fkSegmentation[cath1]->PadByPosition(pad->Position().X(),pad->Position().Y(),kFALSE);
     424           0 :       if (!mpPad.IsValid()) continue;
     425             :       //if (nFlags == 1 && pad->Charge() < fgkZeroSuppression * 3) continue;
     426           0 :       if (nFlags == 1 && pad->Charge() < 3.05) continue;  // JC: adc -> fc
     427           0 :       AliDebug(2,Form("Releasing the following pad : de,cath,ix,iy %d,%d,%d,%d charge %e",
     428             :                       fDetElemId,pad->Cathode(),pad->Ix(),pad->Iy(),pad->Charge()));
     429           0 :       toBeRemoved.AddLast(pad);
     430           0 :       fPreCluster->Pad(i)->Release();
     431           0 :     }
     432           0 :     Int_t nRemove = toBeRemoved.GetEntriesFast();
     433           0 :     for ( Int_t i = 0; i < nRemove; ++i )
     434             :     {
     435           0 :       cluster->RemovePad(static_cast<AliMUONPad*>(toBeRemoved.UncheckedAt(i)));
     436             :     }
     437           0 :   } 
     438             :   
     439             :   // Check correlations of cathode charges
     440           0 :   if ( !cluster->IsSaturated() && cluster->ChargeAsymmetry() > 1 )
     441             :   {
     442             :     // big difference
     443           0 :     Int_t cathode = cluster->MaxRawChargeCathode();
     444             :     Int_t imin(-1);
     445             :     Int_t imax(-1);
     446             :     Double_t cmax(0);
     447             :     Double_t cmin(1E9);
     448             :     
     449             :     // get min and max pad charges on the cathode opposite to the 
     450             :     // max pad (given by MaxRawChargeCathode())
     451             :     //
     452           0 :     Int_t mult = cluster->Multiplicity();
     453           0 :     for ( Int_t i = 0; i < mult; ++i )
     454             :     {
     455           0 :       AliMUONPad* pad = cluster->Pad(i);
     456           0 :       if ( pad->Cathode() != cathode || !pad->IsReal() )
     457             :       {
     458             :         // only consider pads in the opposite cathode, and
     459             :         // only consider real pads (i.e. exclude the virtual ones)
     460           0 :         continue;
     461             :       }
     462           0 :       if ( pad->Charge() < cmin )
     463             :       {
     464           0 :         cmin = pad->Charge();
     465             :         imin = i;
     466           0 :         if (imax < 0) {
     467             :           imax = imin;
     468             :           cmax = cmin;
     469           0 :         }
     470             :       }
     471           0 :       else if ( pad->Charge() > cmax )
     472             :       {
     473           0 :         cmax = pad->Charge();
     474             :         imax = i;
     475           0 :       }      
     476           0 :     }
     477           0 :     AliDebug(2,Form("Pad imin,imax %d,%d cmin,cmax %e,%e",
     478             :                     imin,imax,cmin,cmax));
     479             :     //
     480             :     // arrange pads according to their distance to the max, normalized
     481             :     // to the pad size
     482           0 :     Double_t* dist = new Double_t[mult];
     483             :     Double_t dxMin(1E9);
     484             :     Double_t dyMin(1E9);
     485             :     Double_t dmin(0);
     486             :     
     487           0 :     AliMUONPad* padmax = cluster->Pad(imax);
     488             :     
     489           0 :     for ( Int_t i = 0; i < mult; ++i )
     490             :     {
     491           0 :       dist[i] = 0.0;
     492           0 :       if ( i == imax) continue;
     493           0 :       AliMUONPad* pad = cluster->Pad(i);
     494           0 :       if ( pad->Cathode() != cathode || !pad->IsReal() ) continue;
     495           0 :       Double_t dx = (pad->X()-padmax->X())/padmax->DX()/2.0;
     496           0 :       Double_t dy = (pad->Y()-padmax->Y())/padmax->DY()/2.0;
     497           0 :       dist[i] = TMath::Sqrt(dx*dx+dy*dy);
     498           0 :       if ( i == imin )
     499             :       {
     500           0 :         dmin = dist[i] + 1E-3; // distance to the pad with minimum charge
     501             :         dxMin = dx;
     502             :         dyMin = dy;
     503           0 :       }      
     504           0 :     }
     505             :     
     506           0 :     TMath::Sort(mult,dist,flags,kFALSE); // in ascending order
     507             :     Double_t xmax(-1), distPrev(999);
     508           0 :     TObjArray toBeRemoved;
     509             :     
     510           0 :     for ( Int_t i = 0; i < mult; ++i )
     511             :     {
     512           0 :       Int_t indx = flags[i];
     513           0 :       AliMUONPad* pad = cluster->Pad(indx);
     514           0 :       if ( pad->Cathode() != cathode || !pad->IsReal() ) continue;
     515           0 :       if ( dist[indx] > dmin )
     516             :       {
     517             :         // farther than the minimum pad
     518           0 :         Double_t dx = (pad->X()-padmax->X())/padmax->DX()/2.0;
     519           0 :         Double_t dy = (pad->Y()-padmax->Y())/padmax->DY()/2.0;
     520           0 :         dx *= dxMin;
     521           0 :         dy *= dyMin;
     522           0 :         if (dx >= 0 && dy >= 0) continue;
     523           0 :         if (TMath::Abs(dx) > TMath::Abs(dy) && dx >= 0) continue;
     524           0 :         if (TMath::Abs(dy) > TMath::Abs(dx) && dy >= 0) continue;        
     525           0 :       }
     526           0 :       if (dist[indx] > distPrev + 1) break; // overstepping empty pads
     527           0 :       if ( pad->Charge() <= cmax || TMath::Abs(dist[indx]-xmax) < 1E-3 )
     528             :       {
     529             :         // release pad
     530           0 :         if (TMath::Abs(dist[indx]-xmax) < 1.e-3) 
     531             :         {
     532           0 :           cmax = TMath::Max(pad->Charge(),cmax);
     533           0 :         }
     534             :         else
     535             :         {
     536             :           cmax = pad->Charge();
     537             :         }
     538           0 :         xmax = dist[indx];
     539             :         distPrev = dist[indx];
     540           0 :         AliDebug(2,Form("Releasing the following pad : de,cath,ix,iy %d,%d,%d,%d charge %e",
     541             :                         fDetElemId,pad->Cathode(),pad->Ix(),pad->Iy(),
     542             :                         pad->Charge()));
     543             :   
     544           0 :         toBeRemoved.AddLast(pad);
     545           0 :         fPreCluster->Pad(indx)->Release();
     546           0 :       }
     547           0 :     }
     548           0 :     Int_t nRemove = toBeRemoved.GetEntriesFast();
     549           0 :     for ( Int_t i = 0; i < nRemove; ++i )
     550             :     {
     551           0 :       cluster->RemovePad(static_cast<AliMUONPad*>(toBeRemoved.UncheckedAt(i)));
     552             :     }    
     553           0 :     delete[] dist;
     554           0 :   } // if ( !cluster->IsSaturated() && 
     555             :   
     556           0 :   delete[] flags;
     557             :   
     558           0 :   AliDebug(2,"End of CheckPreClusterTwoCathodes=");
     559             :   //StdoutToAliDebug(2,cluster->Print("full"));
     560             : 
     561           0 :   return cluster;    
     562           0 : }
     563             : 
     564             : //_____________________________________________________________________________
     565             : void
     566             : AliMUONClusterFinderPeakFit::CheckOverlaps()
     567             : {
     568             :   /// For debug only : check if some pixels overlap...
     569             :   
     570           0 :   Int_t nPix = fPixArray->GetLast()+1;
     571             :   Int_t dummy(0);
     572             :   
     573           0 :   for ( Int_t i = 0; i < nPix; ++i )
     574             :   {
     575           0 :     AliMUONPad* pixelI = Pixel(i);
     576           0 :     AliMUONPad pi(dummy,dummy,dummy,dummy,
     577           0 :                   pixelI->Coord(0),pixelI->Coord(1),
     578           0 :                   pixelI->Size(0),pixelI->Size(1),0.0);
     579             :     
     580           0 :     for ( Int_t j = i+1; j < nPix; ++j )
     581             :     {
     582           0 :       AliMUONPad* pixelJ = Pixel(j);
     583           0 :       AliMUONPad pj(dummy,dummy,dummy,dummy,
     584           0 :                     pixelJ->Coord(0),pixelJ->Coord(1),
     585           0 :                     pixelJ->Size(0),pixelJ->Size(1),0.0);  
     586           0 :       AliMpArea area;
     587             :       
     588           0 :       if ( AliMUONPad::AreOverlapping(pi,pj,fgkDecreaseSize,area) )
     589             :       {
     590           0 :         AliInfo(Form("The following 2 pixels (%d and %d) overlap !",i,j));
     591             :         /*
     592             :         StdoutToAliInfo(pixelI->Print();
     593             :                         cout << " Surface = " << pixelI->Size(0)*pixelI->Size(1)*4 << endl;
     594             :                         pixelJ->Print();
     595             :                         cout << " Surface = " << pixelJ->Size(0)*pixelJ->Size(1)*4 << endl;
     596             :                         cout << " Area surface = " << area.Dimensions().X()*area.Dimensions().Y()*4 << endl;
     597             :                         cout << "-------" << endl;
     598             :                         );
     599             :         */        
     600             :       }
     601           0 :     }    
     602           0 :   }
     603           0 : }
     604             : 
     605             : //_____________________________________________________________________________
     606             : void AliMUONClusterFinderPeakFit::BuildPixArray(AliMUONCluster& cluster)
     607             : {
     608             :   /// Build pixel array 
     609             :   
     610           0 :   Int_t npad = cluster.Multiplicity();
     611           0 :   if (npad<=0) 
     612             :   {
     613           0 :     AliWarning("Got no pad at all ?!");
     614           0 :   }
     615             :   
     616           0 :   fPixArray->Delete();
     617           0 :   BuildPixArrayOneCathode(cluster);
     618             :   
     619             : //  StdoutToAliDebug(2,cout << "End of BuildPixelArray:" << endl;
     620             : //                   fPixArray->Print(););
     621             :   //CheckOverlaps();//FIXME : this is for debug only. Remove it.
     622           0 : }
     623             : 
     624             : //_____________________________________________________________________________
     625             : void AliMUONClusterFinderPeakFit::BuildPixArrayOneCathode(AliMUONCluster& cluster)
     626             : {
     627             :   /// Build the pixel array
     628             : 
     629             : //  AliDebug(2,Form("cluster.Multiplicity=%d",cluster.Multiplicity()));
     630             : 
     631           0 :   TVector2 dim = cluster.MinPadDimensions (-1, kFALSE);
     632           0 :   Double_t width[2] = {dim.X(), dim.Y()}, xy0[2] = { 0.0, 0.0 };
     633           0 :   Int_t found[2] = {0}, mult = cluster.Multiplicity();
     634             : 
     635           0 :   for ( Int_t i = 0; i < mult; ++i) {
     636           0 :     AliMUONPad* pad = cluster.Pad(i);
     637           0 :     for (Int_t j = 0; j < 2; ++j) {
     638           0 :       if (found[j] == 0 && TMath::Abs(pad->Size(j)-width[j]) < fgkDistancePrecision) { 
     639           0 :         xy0[j] = pad->Coord(j);
     640           0 :         found[j] = 1;
     641           0 :       }
     642             :     }
     643           0 :     if (found[0] && found[1]) break;
     644           0 :   }
     645             : 
     646           0 :   Double_t min[2], max[2];
     647             :   Int_t cath0 = 0, cath1 = 1;
     648           0 :   if (cluster.Multiplicity(0) == 0) cath0 = 1;
     649           0 :   else if (cluster.Multiplicity(1) == 0) cath1 = 0;
     650             : 
     651           0 :   Double_t leftDownX, leftDownY;
     652           0 :   cluster.Area(cath0).LeftDownCorner(leftDownX, leftDownY);
     653           0 :   Double_t rightUpX, rightUpY; 
     654           0 :   cluster.Area(cath0).RightUpCorner(rightUpX, rightUpY);
     655           0 :   min[0] = leftDownX;
     656           0 :   min[1] = leftDownY;
     657           0 :   max[0] = rightUpX;
     658           0 :   max[1] = rightUpY;
     659           0 :   if (cath1 != cath0) {
     660           0 :     cluster.Area(cath1).LeftDownCorner(leftDownX, leftDownY);
     661           0 :     cluster.Area(cath1).RightUpCorner(rightUpX, rightUpY);
     662           0 :     min[0] = TMath::Max (min[0], leftDownX);
     663           0 :     min[1] = TMath::Max (min[1], leftDownY);
     664           0 :     max[0] = TMath::Min (max[0], rightUpX);
     665           0 :     max[1] = TMath::Min (max[1], rightUpY);
     666           0 :   }
     667             : 
     668             :   // Adjust limits
     669           0 :   if (cath0 != cath1) {
     670           0 :     TVector2 dim0 = cluster.MinPadDimensions (0, -1, kFALSE);
     671           0 :     TVector2 dim1 = cluster.MinPadDimensions (1, -1, kFALSE);
     672           0 :     if (TMath::Abs(dim0.Y()-dim1.Y()) < fgkDistancePrecision) {
     673             :       // The same size of pads on both cathodes - check position
     674           0 :       AliMUONPad* pad0 = cluster.Pad(0);
     675           0 :       for ( Int_t i = 1; i < mult; ++i) {
     676           0 :         AliMUONPad* pad = cluster.Pad(i);
     677           0 :         if (pad->Cathode() == pad0->Cathode()) continue;
     678           0 :         Double_t dist = TMath::Abs (pad0->Coord(1) - pad->Coord(1));
     679           0 :         Double_t dd = dist - Int_t(dist/width[1]/2.) * width[1] * 2.;
     680           0 :         if (TMath::Abs(dd/width[1]/2.-0.5) < fgkDistancePrecision) { 
     681             :           // Half pad shift between cathodes
     682           0 :           width[0] /= 2.; 
     683           0 :           width[1] /= 2.;
     684           0 :         }
     685             :         break;
     686             :       }
     687           0 :     }
     688           0 :   }
     689             : 
     690           0 :   Int_t nbins[2];
     691           0 :   for (Int_t i = 0; i < 2; ++i) {
     692           0 :     Double_t dist = (min[i] - xy0[i]) / width[i] / 2;
     693           0 :     if (TMath::Abs(dist) < 1.e-6) dist = -1.e-6;
     694           0 :     min[i] = xy0[i] + (TMath::Nint(dist-TMath::Sign(1.e-6,dist)) 
     695           0 :                        + TMath::Sign(0.5,dist)) * width[i] * 2;
     696           0 :     nbins[i] = TMath::Nint ((max[i] - min[i]) / width[i] / 2);
     697           0 :     if (nbins[i] == 0) ++nbins[i];
     698           0 :     max[i] = min[i] + nbins[i] * width[i] * 2;
     699             :     //cout << dist << " " << min[i] << " " << max[i] << " " << nbins[i] << endl;
     700             :   }
     701             : 
     702             :   // Book histogram
     703           0 :   TH2D *hist1 = new TH2D ("Grid", "", nbins[0], min[0], max[0], nbins[1], min[1], max[1]);
     704           0 :   TH2D *hist2 = new TH2D ("Entries", "", nbins[0], min[0], max[0], nbins[1], min[1], max[1]);
     705           0 :   TAxis *xaxis = hist1->GetXaxis();
     706           0 :   TAxis *yaxis = hist1->GetYaxis();
     707             : 
     708             :   // Fill histogram
     709           0 :   for ( Int_t i = 0; i < mult; ++i) {
     710           0 :     AliMUONPad* pad = cluster.Pad(i);
     711           0 :     Int_t ix0 = xaxis->FindBin(pad->X());
     712           0 :     Int_t iy0 = yaxis->FindBin(pad->Y());
     713           0 :     PadOverHist(0, ix0, iy0, pad, hist1, hist2);
     714             :   }
     715             : 
     716             :   // Store pixels
     717           0 :   for (Int_t i = 1; i <= nbins[0]; ++i) {
     718           0 :     Double_t x = xaxis->GetBinCenter(i);
     719           0 :     for (Int_t j = 1; j <= nbins[1]; ++j) {
     720           0 :       if (hist2->GetBinContent(hist2->GetBin(i,j)) < 0.01525) continue; // JC: adc -> fc
     721           0 :       if (cath0 != cath1) {
     722             :         // Two-sided cluster
     723           0 :         Double_t cont = hist2->GetBinContent(hist2->GetBin(i,j));
     724           0 :         if (cont < 999.) continue;
     725           0 :         if (cont-Int_t(cont/1000.)*1000. < 0.07625) continue; // JC: adc -> fc
     726           0 :       }
     727             :       //if (hist2->GetBinContent(hist2->GetBin(i,j)) < 1.1 && cluster.Multiplicity(0) && 
     728             :       //  cluster.Multiplicity(1)) continue;
     729           0 :       Double_t y = yaxis->GetBinCenter(j);
     730           0 :       Double_t charge = hist1->GetBinContent(hist1->GetBin(i,j));
     731           0 :       AliMUONPad* pixPtr = new AliMUONPad(x, y, width[0], width[1], charge);
     732           0 :       fPixArray->Add(pixPtr);
     733           0 :     }  
     734             :   }
     735             :   /*
     736             :   if (fPixArray->GetEntriesFast() == 1) {
     737             :     // Split pixel into 2
     738             :     AliMUONPad* pixPtr = static_cast<AliMUONPad*> (fPixArray->UncheckedAt(0));
     739             :     pixPtr->SetSize(0,width[0]/2.);
     740             :     pixPtr->Shift(0,-width[0]/4.);
     741             :     pixPtr = new AliMUONPad(pixPtr->X()+width[0], pixPtr->Y(), width[0]/2., width[1], pixPtr->Charge());
     742             :     fPixArray->Add(pixPtr);
     743             :   }
     744             :   */
     745             :   //fPixArray->Print();
     746           0 :   delete hist1;
     747           0 :   delete hist2;
     748           0 : }
     749             : 
     750             : //_____________________________________________________________________________
     751             : void AliMUONClusterFinderPeakFit::PadOverHist(Int_t idir, Int_t ix0, Int_t iy0, AliMUONPad *pad,
     752             :                                               TH2D *hist1, TH2D *hist2)
     753             : {
     754             :   /// "Span" pad over histogram in the direction idir
     755             : 
     756           0 :   TAxis *axis = idir == 0 ? hist1->GetXaxis() : hist1->GetYaxis();
     757           0 :   Int_t nbins = axis->GetNbins(), cath = pad->Cathode();
     758           0 :   Double_t bin = axis->GetBinWidth(1), amask = TMath::Power(1000.,cath*1.);
     759             : 
     760           0 :   Int_t nbinPad = (Int_t)(pad->Size(idir)/bin*2+fgkDistancePrecision) + 1; // number of bins covered by pad
     761             : 
     762           0 :   for (Int_t i = 0; i < nbinPad; ++i) {
     763           0 :     Int_t ixy = idir == 0 ? ix0 + i : iy0 + i;
     764           0 :     if (ixy > nbins) break;
     765           0 :     Double_t lowEdge = axis->GetBinLowEdge(ixy);
     766           0 :     if (lowEdge + fgkDistancePrecision > pad->Coord(idir) + pad->Size(idir)) break;
     767           0 :     if (idir == 0) PadOverHist(1, ixy, iy0, pad, hist1, hist2); // span in the other direction
     768             :     else {
     769             :       // Fill histogram
     770           0 :       Double_t cont = pad->Charge();
     771           0 :       if (hist2->GetBinContent(hist2->GetBin(ix0, ixy)) > 0.01525) // JC: adc -> fc
     772           0 :         cont = TMath::Min (hist1->GetBinContent(hist1->GetBin(ix0, ixy)), cont) 
     773           0 :           + TMath::Min (TMath::Max(hist1->GetBinContent(hist1->GetBin(ix0, ixy)),cont)*0.1, 1.525); // JC: adc -> fc
     774           0 :       hist1->SetBinContent(hist1->GetBin(ix0, ixy), cont);
     775           0 :       hist2->SetBinContent(hist2->GetBin(ix0, ixy), hist2->GetBinContent( hist2->GetBin(ix0, ixy))+amask);
     776             :     }
     777           0 :   }
     778             : 
     779           0 :   for (Int_t i = -1; i > -nbinPad; --i) {
     780           0 :     Int_t ixy = idir == 0 ? ix0 + i : iy0 + i;
     781           0 :     if (ixy < 1) break;
     782           0 :     Double_t upEdge = axis->GetBinUpEdge(ixy);
     783           0 :     if (upEdge - fgkDistancePrecision < pad->Coord(idir) - pad->Size(idir)) break;
     784           0 :     if (idir == 0) PadOverHist(1, ixy, iy0, pad, hist1, hist2); // span in the other direction
     785             :     else {
     786             :       // Fill histogram
     787           0 :       Double_t cont = pad->Charge();
     788           0 :       if (hist2->GetBinContent(hist2->GetBin(ix0, ixy)) > 0.01525) // JC: adc -> fc 
     789           0 :         cont = TMath::Min (hist1->GetBinContent(hist1->GetBin(ix0, ixy)), cont)
     790           0 :           + TMath::Min (TMath::Max(hist1->GetBinContent(hist1->GetBin(ix0, ixy)),cont)*0.1,1.525); // JC: adc -> fc
     791           0 :       hist1->SetBinContent(hist1->GetBin(ix0, ixy), cont);
     792           0 :       hist2->SetBinContent(hist2->GetBin(ix0, ixy), hist2->GetBinContent( hist2->GetBin(ix0, ixy))+amask);
     793             :     }
     794           0 :   }
     795           0 : }
     796             : 
     797             : //_____________________________________________________________________________
     798             : Int_t AliMUONClusterFinderPeakFit::FindLocalMaxima(TObjArray *pixArray, Int_t *localMax, Double_t *maxVal)
     799             : {
     800             : /// Find local maxima in pixel space 
     801             : 
     802           0 :   AliDebug(1,Form("nPix=%d",pixArray->GetLast()+1));
     803             : 
     804             :   //TH2D *hist = NULL;
     805             :   //delete ((TH2D*) gROOT->FindObject("anode"));
     806             :   //if (pixArray == fPixArray) hist = (TH2D*) gROOT->FindObject("anode");
     807             :   //else { hist = (TH2D*) gROOT->FindObject("anode1"); cout << hist << endl; }
     808             :   //if (hist) hist->Delete();
     809           0 :   delete fHistAnode;
     810             :  
     811           0 :   Double_t xylim[4] = {999, 999, 999, 999};
     812             : 
     813           0 :   Int_t nPix = pixArray->GetEntriesFast();
     814             :   
     815           0 :   if ( nPix <= 0 ) return 0;
     816             : 
     817             :   AliMUONPad *pixPtr = 0;
     818           0 :   for (Int_t ipix = 0; ipix < nPix; ++ipix) {
     819           0 :     pixPtr = (AliMUONPad*) pixArray->UncheckedAt(ipix);
     820           0 :     for (Int_t i = 0; i < 4; ++i) 
     821           0 :          xylim[i] = TMath::Min (xylim[i], (i%2 ? -1 : 1)*pixPtr->Coord(i/2));
     822             :   }
     823           0 :   for (Int_t i = 0; i < 4; ++i) xylim[i] -= pixPtr->Size(i/2); 
     824             : 
     825           0 :   Int_t nx = TMath::Nint ((-xylim[1]-xylim[0])/pixPtr->Size(0)/2);
     826           0 :   Int_t ny = TMath::Nint ((-xylim[3]-xylim[2])/pixPtr->Size(1)/2);
     827           0 :   if (pixArray == fPixArray) fHistAnode = new TH2D("anode","anode",nx,xylim[0],-xylim[1],ny,xylim[2],-xylim[3]);
     828           0 :   else fHistAnode = new TH2D("anode1","anode1",nx,xylim[0],-xylim[1],ny,xylim[2],-xylim[3]);
     829           0 :   for (Int_t ipix = 0; ipix < nPix; ++ipix) {
     830           0 :     pixPtr = (AliMUONPad*) pixArray->UncheckedAt(ipix);
     831           0 :     fHistAnode->Fill(pixPtr->Coord(0), pixPtr->Coord(1), pixPtr->Charge());
     832             :   }
     833             : //  if (fDraw && pixArray == fPixArray) fDraw->DrawHist("c2", hist);
     834             : 
     835           0 :   Int_t nMax = 0, indx, nxy = ny * nx;
     836           0 :   Int_t *isLocalMax = new Int_t[nxy];
     837           0 :   for (Int_t i = 0; i < nxy; ++i) isLocalMax[i] = 0; 
     838             : 
     839           0 :   for (Int_t i = 1; i <= ny; ++i) {
     840           0 :     indx = (i-1) * nx;
     841           0 :     for (Int_t j = 1; j <= nx; ++j) {
     842           0 :       if (fHistAnode->GetBinContent(fHistAnode->GetBin(j,i)) < 0.07625) continue;  // JC: adc -> fc
     843             :       //if (isLocalMax[indx+j-1] < 0) continue;
     844           0 :       if (isLocalMax[indx+j-1] != 0) continue;
     845           0 :       FlagLocalMax(fHistAnode, i, j, isLocalMax);
     846           0 :     }
     847             :   }
     848             : 
     849           0 :   for (Int_t i = 1; i <= ny; ++i) {
     850           0 :     indx = (i-1) * nx;
     851           0 :     for (Int_t j = 1; j <= nx; ++j) {
     852           0 :       if (isLocalMax[indx+j-1] > 0) { 
     853           0 :         localMax[nMax] = indx + j - 1; 
     854           0 :         maxVal[nMax++] = fHistAnode->GetBinContent(fHistAnode->GetBin(j,i));
     855           0 :         if (nMax > 99) break;
     856             :       }
     857             :     }
     858           0 :     if (nMax > 99) {
     859           0 :       AliError(" Too many local maxima !!!");
     860           0 :       break;
     861             :     }
     862             :   }
     863           0 :   if (fDebug) cout << " Local max: " << nMax << endl;
     864           0 :   delete [] isLocalMax; 
     865             :   return nMax;
     866           0 : }
     867             : 
     868             : //_____________________________________________________________________________
     869             : void AliMUONClusterFinderPeakFit::FlagLocalMax(TH2D *hist, Int_t i, Int_t j, Int_t *isLocalMax)
     870             : {
     871             : /// Flag pixels (whether or not local maxima)
     872             : 
     873           0 :   Int_t nx = hist->GetNbinsX();
     874           0 :   Int_t ny = hist->GetNbinsY();
     875           0 :   Int_t cont = TMath::Nint (hist->GetBinContent(hist->GetBin(j,i)));
     876           0 :   Int_t cont1 = 0, indx = (i-1)*nx+j-1, indx1 = 0, indx2 = 0;
     877             : 
     878           0 :   Int_t ie = i + 2, je = j + 2;
     879           0 :   for (Int_t i1 = i-1; i1 < ie; ++i1) {
     880           0 :     if (i1 < 1 || i1 > ny) continue;
     881           0 :     indx1 = (i1 - 1) * nx;
     882           0 :     for (Int_t j1 = j-1; j1 < je; ++j1) {
     883           0 :       if (j1 < 1 || j1 > nx) continue;
     884           0 :       if (i == i1 && j == j1) continue;
     885           0 :       indx2 = indx1 + j1 - 1;
     886           0 :       cont1 = TMath::Nint (hist->GetBinContent(hist->GetBin(j1,i1)));
     887           0 :       if (cont < cont1) { isLocalMax[indx] = -1; return; }
     888           0 :       else if (cont > cont1) isLocalMax[indx2] = -1;
     889             :       else { // the same charge
     890           0 :         isLocalMax[indx] = 1; 
     891           0 :         if (isLocalMax[indx2] == 0) {
     892           0 :           FlagLocalMax(hist, i1, j1, isLocalMax);
     893           0 :           if (isLocalMax[indx2] < 0) { isLocalMax[indx] = -1; return; }
     894           0 :           else isLocalMax[indx2] = -1;
     895           0 :         }
     896             :       } 
     897             :     }
     898             :   }
     899           0 :   isLocalMax[indx] = 1; // local maximum
     900           0 : }
     901             : 
     902             : //_____________________________________________________________________________
     903             : void AliMUONClusterFinderPeakFit::FindClusterFit(AliMUONCluster& cluster, const Int_t *localMax, 
     904             :                                                  const Int_t *maxPos, Int_t nMax)
     905             : {
     906             : /// Fit pad charge distribution with nMax hit hypothesis
     907             : 
     908             :   //if (cluster.Multiplicity(0) == 0 || cluster.Multiplicity(1) == 0) cout << cluster.Multiplicity(0) << " " << cluster.Multiplicity(1) << " " << cluster.Charge() << " " << cluster.Charge(0) << " " << cluster.Charge(1) << " " << endl;
     909             : 
     910             :   //TH2D *hist = (TH2D*) gROOT->FindObject("anode");
     911           0 :   Int_t nx = fHistAnode->GetNbinsX();
     912             :   //Int_t ny = hist->GetNbinsY();
     913           0 :   Double_t xmin = fHistAnode->GetXaxis()->GetXmin(); //- hist->GetXaxis()->GetBinWidth(1);
     914           0 :   Double_t xmax = fHistAnode->GetXaxis()->GetXmax(); //+ hist->GetXaxis()->GetBinWidth(1);
     915           0 :   Double_t ymin = fHistAnode->GetYaxis()->GetXmin(); //- hist->GetYaxis()->GetBinWidth(1);
     916           0 :   Double_t ymax = fHistAnode->GetYaxis()->GetXmax(); //+ hist->GetYaxis()->GetBinWidth(1);
     917             : 
     918           0 :   TVirtualFitter* fitter = TVirtualFitter::Fitter(0,nMax*3);
     919           0 :   fitter->Clear("");
     920           0 :   fitter->SetFCN(FitFunction);
     921             : 
     922             :   Float_t stepX = 0.01; // cm
     923             :   Float_t stepY = 0.01; // cm
     924             :   Float_t stepQ = 0.01; // 
     925             :   
     926           0 :   Double_t args[10] = {-1.}; // disable printout
     927             :   
     928           0 :   fitter->ExecuteCommand("SET PRINT",args,1);
     929           0 :   fitter->ExecuteCommand("SET NOW",args,0); // no warnings
     930             :   
     931             :   Int_t indx = 0;
     932           0 :   fNMax = nMax;
     933           0 :   for (Int_t i = 0; i < nMax; ++i) {
     934           0 :     Int_t ic = localMax[maxPos[i]] / nx + 1;
     935           0 :     Int_t jc = localMax[maxPos[i]] % nx + 1;
     936           0 :     Double_t yc = fHistAnode->GetYaxis()->GetBinCenter(ic);
     937           0 :     Double_t xc = fHistAnode->GetXaxis()->GetBinCenter(jc);
     938           0 :     indx = 3 * i;
     939           0 :     fitter->SetParameter(indx,"Hit X position",xc,stepX,xmin,xmax);
     940           0 :     fitter->SetParameter(indx+1,"Hit Y position",yc,stepY,ymin,ymax);
     941           0 :     fitter->SetParameter(indx+2,"Hit contribution",0.6,stepQ,0.,1.);
     942             :   }
     943           0 :   fitter->SetParameter(indx+2,"Hit contribution",0.,0.,0,0);
     944             :   //fitter->SetParameter(8,"Number of hits",nMax,0.,0,0);
     945             : 
     946           0 :   TObjArray userObjects;
     947             :   
     948           0 :   userObjects.Add(&cluster);
     949           0 :   userObjects.Add(fMathieson);
     950           0 :   userObjects.Add(this);
     951             :   
     952           0 :   fitter->SetObjectFit(&userObjects);
     953             :   
     954           0 :   args[0] = 500.;
     955           0 :   args[1] = 1.;
     956           0 :   /*Int_t stat =*/ fitter->ExecuteCommand("MIGRAD",args,2);
     957             :   //if (stat) { cout << " stat = " << stat << " " << fDetElemId << endl; /*exit(0);*/ }
     958             :   //Int_t nvpar, nparx;
     959             :   //Double_t amin, edm, errdef; 
     960             :   //fitter->GetStats(amin, edm, errdef, nvpar, nparx);
     961             :   //cout << amin << endl;
     962             : 
     963           0 :   Double_t qTot = cluster.Charge(), par[9] = {0.}, err[9] = {0.}, coef = 0.;
     964             :   //par[8] = nMax;
     965           0 :   for (Int_t j = 0; j < nMax; ++j) {
     966           0 :     indx = 3 * j;
     967           0 :     par[indx+2] = fitter->GetParameter(indx+2);
     968           0 :     coef = Param2Coef(j, coef, par, nMax);
     969           0 :     par[indx] = fitter->GetParameter(indx);
     970           0 :     par[indx+1] = fitter->GetParameter(indx+1);
     971           0 :     err[indx] = fitter->GetParError(indx);
     972           0 :     err[indx+1] = fitter->GetParError(indx+1);
     973             :       
     974           0 :     if ( coef*qTot >= 2.135 ) // JC: adc -> fc
     975             :     {
     976           0 :       AliMUONCluster* cluster1 = new AliMUONCluster(cluster);
     977             :       
     978           0 :       cluster1->SetCharge(coef*qTot,coef*qTot);
     979             :       
     980           0 :       cluster1->SetPosition(TVector2(par[indx],par[indx+1]),TVector2(err[indx],err[indx+1]));
     981           0 :       cluster1->SetChi2(0.);
     982             :       
     983             :       // FIXME: we miss some information in this cluster, as compared to 
     984             :       // the original AddRawCluster code.
     985             :       
     986           0 :       AliDebug(2,Form("Adding RawCluster detElemId %4d mult %2d charge %5d (xl,yl)=(%9.6g,%9.6g)",
     987             :                       fDetElemId,cluster1->Multiplicity(),(Int_t)cluster1->Charge(),
     988             :                       cluster1->Position().X(),cluster1->Position().Y()));
     989             :         
     990           0 :       fClusterList.Add(cluster1);
     991           0 :     }
     992             :   }
     993           0 : }
     994             : 
     995             : //_____________________________________________________________________________
     996             : void AliMUONClusterFinderPeakFit::FindClusterCOG(AliMUONCluster& cluster, 
     997             :                                                  const Int_t *localMax, Int_t iMax)
     998             : {
     999             : /// Find COG of pad charge distribution around local maximum \a iMax 
    1000             : 
    1001             :   //TH2D *hist = (TH2D*) gROOT->FindObject("anode");
    1002             :   /* Just for check
    1003             :   TCanvas* c = new TCanvas("Anode","Anode",800,600);
    1004             :   c->cd();
    1005             :   hist->Draw("lego1Fb"); // debug
    1006             :   c->Update();
    1007             :   Int_t tmp;
    1008             :   cin >> tmp;
    1009             :   */
    1010           0 :   Int_t nx = fHistAnode->GetNbinsX();
    1011             :   //Int_t ny = hist->GetNbinsY();
    1012           0 :   Int_t ic = localMax[iMax] / nx + 1;
    1013           0 :   Int_t jc = localMax[iMax] % nx + 1;
    1014             : 
    1015             :   // Get min pad dimensions for the precluster
    1016             :   Int_t nSides = 2;
    1017           0 :   if (cluster.Multiplicity(0) == 0 || cluster.Multiplicity(1) == 0) nSides = 1;
    1018           0 :   TVector2 dim0 = cluster.MinPadDimensions(0, -1, kFALSE);
    1019           0 :   TVector2 dim1 = cluster.MinPadDimensions(1, -1, kFALSE);
    1020             :   //Double_t width[2][2] = {{dim0.X(), dim0.Y()},{dim1.X(),dim1.Y()}};
    1021           0 :   Int_t nonb[2] = {1, 0}; // coordinate index vs cathode
    1022           0 :   if (nSides == 1 || dim0.X() < dim1.X() - fgkDistancePrecision) {
    1023           0 :     nonb[0] = 0;
    1024           0 :     nonb[1] = 1;
    1025           0 :   }
    1026             : 
    1027             :   // Drop all pixels from the array - pick up only the ones from the cluster
    1028             :   //fPixArray->Delete();
    1029             : 
    1030           0 :   Double_t wx = fHistAnode->GetXaxis()->GetBinWidth(1)/2; 
    1031           0 :   Double_t wy = fHistAnode->GetYaxis()->GetBinWidth(1)/2;  
    1032           0 :   Double_t yc = fHistAnode->GetYaxis()->GetBinCenter(ic);
    1033           0 :   Double_t xc = fHistAnode->GetXaxis()->GetBinCenter(jc);
    1034           0 :   Double_t cont = fHistAnode->GetBinContent(fHistAnode->GetBin(jc,ic));
    1035           0 :   AliMUONPad pixel(xc, yc, wx, wy, cont);
    1036           0 :   if (fDebug) pixel.Print("full"); 
    1037             : 
    1038           0 :   Int_t npad = cluster.Multiplicity();
    1039             :   
    1040             :   // Pick up pads which overlap with the maximum pixel and find pads with the max signal
    1041           0 :   Double_t qMax[2] = {0}; 
    1042           0 :   AliMUONPad *matrix[2][3] = {{0x0,0x0,0x0},{0x0,0x0,0x0}};
    1043           0 :   for (Int_t j = 0; j < npad; ++j) 
    1044             :   {
    1045           0 :     AliMUONPad* pad = cluster.Pad(j);
    1046           0 :     if ( Overlap(*pad,pixel) )
    1047             :     {
    1048           0 :       if (fDebug) { cout << j << " "; pad->Print("full"); }
    1049           0 :       if (pad->Charge() > qMax[pad->Cathode()]) {
    1050           0 :         qMax[pad->Cathode()] = pad->Charge();
    1051           0 :         matrix[pad->Cathode()][1] = pad;
    1052           0 :         if (nSides == 1) matrix[!pad->Cathode()][1] = pad;
    1053             :       }
    1054             :     }
    1055             :   }
    1056             :   //if (nSides == 2 && (matrix[0][1] == 0x0 || matrix[1][1] == 0x0)) return; // ???
    1057             : 
    1058             :   // Find neighbours of maxima to have 3 pads per direction (if possible)
    1059           0 :   for (Int_t j = 0; j < npad; ++j) 
    1060             :   {
    1061           0 :     AliMUONPad* pad = cluster.Pad(j);
    1062           0 :     Int_t cath = pad->Cathode();
    1063           0 :     if (pad == matrix[cath][1]) continue;
    1064           0 :     Int_t nLoops = 3 - nSides;
    1065             : 
    1066           0 :     for (Int_t k = 0; k < nLoops; ++k) {
    1067             :       Int_t cath1 = cath;
    1068           0 :       if (k) cath1 = !cath;
    1069             : 
    1070             :       // Check the coordinate corresponding to the cathode (bending or non-bending case)
    1071           0 :       Double_t dist = pad->Coord(nonb[cath1]) - matrix[cath][1]->Coord(nonb[cath1]);
    1072           0 :       Double_t dir = TMath::Sign (1., dist);
    1073           0 :       dist = TMath::Abs(dist) - pad->Size(nonb[cath1]) - matrix[cath][1]->Size(nonb[cath1]);
    1074             : 
    1075           0 :       if (TMath::Abs(dist) < fgkDistancePrecision) {
    1076             :         // Check the other coordinate
    1077           0 :         dist = pad->Coord(!nonb[cath1]) - matrix[cath1][1]->Coord(!nonb[cath1]);
    1078           0 :         if (TMath::Abs(dist) > 
    1079           0 :             TMath::Max(pad->Size(!nonb[cath1]), matrix[cath1][1]->Size(!nonb[cath1])) - fgkDistancePrecision) break;
    1080           0 :         Int_t idir = TMath::Nint (dir);
    1081           0 :         if (matrix[cath1][1+idir] == 0x0) matrix[cath1][1+idir] = pad;
    1082           0 :         else if (pad->Charge() > matrix[cath1][1+idir]->Charge()) matrix[cath1][1+idir] = pad; // diff. segmentation
    1083             :         //cout << pad->Coord(nonb[cath1]) << " " << pad->Coord(!nonb[cath1]) << " " << pad->Size(nonb[cath1]) << " " << pad->Size(!nonb[cath1]) << " " << pad->Charge() << endl ;
    1084             :         break;
    1085             :       }
    1086           0 :     }
    1087           0 :   }
    1088             : 
    1089           0 :   Double_t coord[2] = {0.}, qAver = 0.;
    1090           0 :   for (Int_t i = 0; i < 2; ++i) {
    1091             :     Double_t q = 0.;
    1092             :     Double_t coordQ = 0.;
    1093           0 :     Int_t cath = matrix[i][1]->Cathode();
    1094           0 :     if (i && nSides == 1) cath = !cath;
    1095           0 :     for (Int_t j = 0; j < 3; ++j) {
    1096           0 :       if (matrix[i][j] == 0x0) continue;
    1097           0 :       Double_t dq = matrix[i][j]->Charge();
    1098           0 :       q += dq;
    1099           0 :       coordQ += dq * matrix[i][j]->Coord(nonb[cath]);
    1100             :       //coordQ += (matrix[i][j]->Charge() * matrix[i][j]->Coord(nonb[cath]));
    1101           0 :     }
    1102           0 :     coord[cath] = coordQ / q;
    1103           0 :     qAver = TMath::Max (qAver, q);
    1104             :   }
    1105             : 
    1106             :   //qAver = TMath::Sqrt(qAver);
    1107           0 :   if ( qAver >= 2.135 ) // JC: adc -> fc
    1108             :   {
    1109             :     
    1110           0 :     AliMUONCluster* cluster1 = new AliMUONCluster(cluster);
    1111             :       
    1112           0 :     cluster1->SetCharge(qAver,qAver);
    1113           0 :     if (nonb[0] == 1) 
    1114           0 :       cluster1->SetPosition(TVector2(coord[1],coord[0]),TVector2(0.,0.));
    1115             :     else 
    1116           0 :       cluster1->SetPosition(TVector2(coord[0],coord[1]),TVector2(0.,0.));
    1117             : 
    1118           0 :     cluster1->SetChi2(0.);
    1119             :       
    1120             :     // FIXME: we miss some information in this cluster, as compared to 
    1121             :     // the original AddRawCluster code.
    1122             :       
    1123           0 :     AliDebug(2,Form("Adding RawCluster detElemId %4d mult %2d charge %5d (xl,yl)=(%9.6g,%9.6g)",
    1124             :                     fDetElemId,cluster1->Multiplicity(),(Int_t)cluster1->Charge(),
    1125             :                     cluster1->Position().X(),cluster1->Position().Y()));
    1126             :         
    1127           0 :     fClusterList.Add(cluster1);
    1128           0 :   }
    1129           0 : }
    1130             : 
    1131             : //_____________________________________________________________________________
    1132             : AliMUONClusterFinderPeakFit&  
    1133             : AliMUONClusterFinderPeakFit::operator=(const AliMUONClusterFinderPeakFit& rhs)
    1134             : {
    1135             : /// Protected assignement operator
    1136             : 
    1137           0 :   if (this == &rhs) return *this;
    1138             : 
    1139           0 :   AliFatal("Not implemented.");
    1140             :     
    1141           0 :   return *this;  
    1142           0 : }    
    1143             : 
    1144             : //_____________________________________________________________________________
    1145             : void AliMUONClusterFinderPeakFit::PadsInXandY(AliMUONCluster& cluster,
    1146             :                                            Int_t &nInX, Int_t &nInY) const
    1147             : {
    1148             :   /// Find number of pads in X and Y-directions (excluding virtual ones and
    1149             :   /// overflows)
    1150             : 
    1151             :   //Int_t statusToTest = 1;
    1152             :   Int_t statusToTest = fgkUseForFit;
    1153             :   
    1154             :   //if ( nInX < 0 ) statusToTest = 0;
    1155           0 :   if ( nInX < 0 ) statusToTest = fgkZero;
    1156             :        
    1157             :   Bool_t mustMatch(kTRUE);
    1158             : 
    1159           0 :   Long_t cn = cluster.NofPads(statusToTest,mustMatch);
    1160             :   
    1161           0 :   nInX = AliMp::PairFirst(cn);
    1162           0 :   nInY = AliMp::PairSecond(cn);
    1163           0 : }
    1164             : 
    1165             : //_____________________________________________________________________________
    1166             : void AliMUONClusterFinderPeakFit::RemovePixel(Int_t i)
    1167             : {
    1168             :   /// Remove pixel at index i
    1169           0 :   AliMUONPad* pixPtr = Pixel(i);
    1170           0 :   fPixArray->RemoveAt(i); 
    1171           0 :   delete pixPtr;
    1172           0 : }
    1173             : 
    1174             : //_____________________________________________________________________________
    1175             : AliMUONPad* 
    1176             : AliMUONClusterFinderPeakFit::Pixel(Int_t i) const
    1177             : {
    1178             :   /// Returns pixel at index i
    1179           0 :   return static_cast<AliMUONPad*>(fPixArray->UncheckedAt(i));
    1180             : }
    1181             : 
    1182             : //_____________________________________________________________________________
    1183             : void 
    1184             : AliMUONClusterFinderPeakFit::Print(Option_t* what) const
    1185             : {
    1186             :   /// printout
    1187           0 :   TString swhat(what);
    1188           0 :   swhat.ToLower();
    1189           0 :   if ( swhat.Contains("precluster") )
    1190             :   {
    1191           0 :     if ( fPreCluster) fPreCluster->Print();
    1192             :   }
    1193           0 : }
    1194             : 
    1195             : 

Generated by: LCOV version 1.11