1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
18 /* History of cvs commits:
20 * $Log: AliPHOSClusterizerv1.cxx,v $
21 * Revision 1.118 2007/12/11 21:23:26 kharlov
22 * Added possibility to swith off unfolding
24 * Revision 1.117 2007/10/18 08:42:05 kharlov
25 * Bad channels cleaned before clusterization
27 * Revision 1.116 2007/10/01 20:24:08 kharlov
30 * Revision 1.115 2007/09/26 14:22:17 cvetan
31 * Important changes to the reconstructor classes. Complete elimination of the run-loaders, which are now steered only from AliReconstruction. Removal of the corresponding Reconstruct() and FillESD() methods.
33 * Revision 1.114 2007/09/06 16:06:44 kharlov
34 * Absence of sorting results in loose of all unfolded clusters
36 * Revision 1.113 2007/08/28 12:55:07 policheh
37 * Loaders removed from the reconstruction code (C.Cheshkov)
39 * Revision 1.112 2007/08/22 09:20:50 hristov
40 * Updated QA classes (Yves)
42 * Revision 1.111 2007/08/08 12:11:28 kharlov
43 * Protection against uninitialized fQADM
45 * Revision 1.110 2007/08/07 14:16:00 kharlov
46 * Quality assurance added (Yves Schutz)
48 * Revision 1.109 2007/07/24 17:20:35 policheh
49 * Usage of RecoParam objects instead of hardcoded parameters in reconstruction.
50 * (See $ALICE_ROOT/PHOS/macros/BeamTest2006/RawReconstruction.C).
52 * Revision 1.108 2007/06/18 07:00:51 kharlov
53 * Bug fix for attempt to use AliPHOSEmcRecPoint after its deletion
55 * Revision 1.107 2007/05/25 14:12:26 policheh
56 * Local to tracking CS transformation added for CPV rec. points
58 * Revision 1.106 2007/05/24 13:01:22 policheh
59 * Local to tracking CS transformation invoked for each EMC rec.point
61 * Revision 1.105 2007/05/02 13:41:22 kharlov
62 * Mode protection against absence of calib.data from AliPHOSCalibData to AliPHOSClusterizerv1::GetCalibrationParameters()
64 * Revision 1.104 2007/04/27 16:55:53 kharlov
65 * Calibration stops if PHOS CDB objects do not exist
67 * Revision 1.103 2007/04/11 11:55:45 policheh
68 * SetDistancesToBadChannels() added.
70 * Revision 1.102 2007/03/28 19:18:15 kharlov
71 * RecPoints recalculation in TSM removed
73 * Revision 1.101 2007/03/06 06:51:27 kharlov
74 * Calculation of cluster properties dep. on vertex posponed to TrackSegmentMaker
76 * Revision 1.100 2007/01/10 11:07:26 kharlov
77 * Raw digits writing to file (B.Polichtchouk)
79 * Revision 1.99 2006/11/07 16:49:51 kharlov
80 * Corrections for next event switch in case of raw data (B.Polichtchouk)
82 * Revision 1.98 2006/10/27 17:14:27 kharlov
83 * Introduce AliDebug and AliLog (B.Polichtchouk)
85 * Revision 1.97 2006/08/29 11:41:19 kharlov
86 * Missing implementation of ctors and = operator are added
88 * Revision 1.96 2006/08/25 16:56:30 kharlov
89 * Compliance with Effective C++
91 * Revision 1.95 2006/08/11 12:36:26 cvetan
92 * Update of the PHOS code needed in order to read and reconstruct the beam test raw data (i.e. without an existing galice.root)
94 * Revision 1.94 2006/08/07 12:27:49 hristov
95 * Removing obsolete code which affected the event numbering scheme
97 * Revision 1.93 2006/08/01 12:20:17 cvetan
98 * 1. Adding a possibility to read and reconstruct an old rcu formatted raw data. This is controlled by an option of AliReconstruction and AliPHOSReconstructor. 2. In case of raw data processing (without galice.root) create the default AliPHOSGeometry object. Most likely this should be moved to the CDB
100 * Revision 1.92 2006/04/29 20:26:46 hristov
101 * Separate EMC and CPV calibration (Yu.Kharlov)
103 * Revision 1.91 2006/04/22 10:30:17 hristov
104 * Add fEnergy to AliPHOSDigit and operate with EMC amplitude in energy units (Yu.Kharlov)
106 * Revision 1.90 2006/04/11 15:22:59 hristov
107 * run number in query set to -1: forces AliCDBManager to use its run number (A.Colla)
109 * Revision 1.89 2006/03/13 14:05:42 kharlov
110 * Calibration objects for EMC and CPV
112 * Revision 1.88 2006/01/11 08:54:52 hristov
113 * Additional protection in case no calibration entry was found
115 * Revision 1.87 2005/11/22 08:46:43 kharlov
116 * Updated to new CDB (Boris Polichtchouk)
118 * Revision 1.86 2005/11/14 21:52:43 hristov
121 * Revision 1.85 2005/09/27 16:08:08 hristov
122 * New version of CDB storage framework (A.Colla)
124 * Revision 1.84 2005/09/21 10:02:47 kharlov
125 * Reading calibration from CDB (Boris Polichtchouk)
127 * Revision 1.82 2005/09/02 15:43:13 kharlov
128 * Add comments in GetCalibrationParameters and Calibrate
130 * Revision 1.81 2005/09/02 14:32:07 kharlov
131 * Calibration of raw data
133 * Revision 1.80 2005/08/24 15:31:36 kharlov
134 * Setting raw digits flag
136 * Revision 1.79 2005/07/25 15:53:53 kharlov
139 * Revision 1.78 2005/05/28 14:19:04 schutz
140 * Compilation warnings fixed by T.P.
144 //*-- Author: Yves Schutz (SUBATECH) & Dmitri Peressounko (SUBATECH & Kurchatov Institute)
145 //////////////////////////////////////////////////////////////////////////////
146 // Clusterization class. Performs clusterization (collects neighbouring active cells) and
147 // unfolds the clusters having several local maxima.
148 // Results are stored in TreeR#, branches PHOSEmcRP (EMC recPoints),
149 // PHOSCpvRP (CPV RecPoints) and AliPHOSClusterizer (Clusterizer with all
150 // parameters including input digits branch title, thresholds etc.)
151 // This TTask is normally called from Reconstructioner, but can as well be used in
154 // root [0] AliPHOSClusterizerv1 * cl = new AliPHOSClusterizerv1(<pointer_to_phos_geometry_onject>)
155 // root [1] cl->Digits2Clusters(digitsTree,clusterTree)
156 // //finds RecPoints in the current event
157 // root [2] cl->SetDigitsBranch("digits2")
158 // //sets another title for Digitis (input) branch
159 // root [3] cl->SetRecPointsBranch("recp2")
160 // //sets another title four output branches
161 // root [4] cl->SetEmcLocalMaxCut(0.03)
162 // //set clusterization parameters
164 // --- ROOT system ---
169 #include "TBenchmark.h"
170 #include "TClonesArray.h"
172 // --- Standard library ---
174 // --- AliRoot header files ---
176 #include "AliConfig.h"
177 #include "AliPHOSGeometry.h"
178 #include "AliPHOSClusterizerv1.h"
179 #include "AliPHOSEmcRecPoint.h"
180 #include "AliPHOSCpvRecPoint.h"
181 #include "AliPHOSDigit.h"
182 #include "AliPHOSDigitizer.h"
183 #include "AliPHOSCalibrationDB.h"
184 #include "AliCDBManager.h"
185 #include "AliCDBStorage.h"
186 #include "AliCDBEntry.h"
187 #include "AliPHOSRecoParam.h"
188 #include "AliPHOSReconstructor.h"
189 #include "AliPHOSCalibData.h"
191 ClassImp(AliPHOSClusterizerv1)
193 //____________________________________________________________________________
194 AliPHOSClusterizerv1::AliPHOSClusterizerv1() :
195 AliPHOSClusterizer(),
196 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
198 fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
199 fEmcClusteringThreshold(0), fCpvClusteringThreshold(0),
200 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
201 fW0CPV(0), fEmcTimeGate(0)
203 // default ctor (to be used mainly by Streamer)
206 fDefaultInit = kTRUE ;
209 //____________________________________________________________________________
210 AliPHOSClusterizerv1::AliPHOSClusterizerv1(AliPHOSGeometry *geom) :
211 AliPHOSClusterizer(geom),
212 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
214 fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
215 fEmcClusteringThreshold(0), fCpvClusteringThreshold(0),
216 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
217 fW0CPV(0), fEmcTimeGate(0)
219 // ctor with the indication of the file where header Tree and digits Tree are stored
223 fDefaultInit = kFALSE ;
226 //____________________________________________________________________________
227 AliPHOSClusterizerv1::~AliPHOSClusterizerv1()
232 //____________________________________________________________________________
233 void AliPHOSClusterizerv1::Digits2Clusters(Option_t *option)
235 // Steering method to perform clusterization for one event
236 // The input is the tree with digits.
237 // The output is the tree with clusters.
239 if(strstr(option,"tim"))
240 gBenchmark->Start("PHOSClusterizer");
242 if(strstr(option,"print")) {
249 AliDebug(2,Form(" ---- Printing clusters (%d)\n",
250 fEMCRecPoints->GetEntries()));
251 if(AliLog::GetGlobalDebugLevel()>1)
252 fEMCRecPoints->Print();
259 if(strstr(option,"deb"))
260 PrintRecPoints(option) ;
262 if(strstr(option,"tim")){
263 gBenchmark->Stop("PHOSClusterizer");
264 AliInfo(Form("took %f seconds for Clusterizing\n",
265 gBenchmark->GetCpuTime("PHOSClusterizer")));
269 //____________________________________________________________________________
270 Bool_t AliPHOSClusterizerv1::FindFit(AliPHOSEmcRecPoint * emcRP, AliPHOSDigit ** maxAt, Float_t * maxAtEnergy,
271 Int_t nPar, Float_t * fitparameters) const
273 // Calls TMinuit to fit the energy distribution of a cluster with several maxima
274 // The initial values for fitting procedure are set equal to the positions of local maxima.
275 // Cluster will be fitted as a superposition of nPar/3 electromagnetic showers
278 gMinuit->mncler(); // Reset Minuit's list of paramters
279 gMinuit->SetPrintLevel(-1) ; // No Printout
280 gMinuit->SetFCN(AliPHOSClusterizerv1::UnfoldingChiSquare) ;
281 // To set the address of the minimization function
283 TList * toMinuit = new TList();
284 toMinuit->AddAt(emcRP,0) ;
285 toMinuit->AddAt(fDigitsArr,1) ;
286 toMinuit->AddAt(fGeom,2) ;
288 gMinuit->SetObjectFit(toMinuit) ; // To tranfer pointer to UnfoldingChiSquare
290 // filling initial values for fit parameters
291 AliPHOSDigit * digit ;
295 Int_t nDigits = (Int_t) nPar / 3 ;
299 for(iDigit = 0; iDigit < nDigits; iDigit++){
300 digit = maxAt[iDigit];
305 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
306 fGeom->RelPosInModule(relid, x, z) ;
308 Float_t energy = maxAtEnergy[iDigit] ;
310 gMinuit->mnparm(index, "x", x, 0.1, 0, 0, ierflg) ;
313 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : x = %f\n", x ) ;
316 gMinuit->mnparm(index, "z", z, 0.1, 0, 0, ierflg) ;
319 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : z =%f\n", z ) ;
322 gMinuit->mnparm(index, "Energy", energy , 0.05*energy, 0., 4.*energy, ierflg) ;
325 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : energy = %f\n", energy ) ;
330 Double_t p0 = 0.1 ; // "Tolerance" Evaluation stops when EDM = 0.0001*p0 ; The number of function call slightly
335 gMinuit->mnexcm("SET STR", &p2, 0, ierflg) ; // force TMinuit to reduce function calls
336 gMinuit->mnexcm("SET GRA", &p1, 1, ierflg) ; // force TMinuit to use my gradient
337 gMinuit->SetMaxIterations(5);
338 gMinuit->mnexcm("SET NOW", &p2 , 0, ierflg) ; // No Warnings
340 gMinuit->mnexcm("MIGRAD", &p0, 0, ierflg) ; // minimize
342 if(ierflg == 4){ // Minimum not found
343 Warning("FindFit", "PHOS Unfolding fit not converged, cluster abandoned\n" );
346 for(index = 0; index < nPar; index++){
349 gMinuit->GetParameter(index, val, err) ; // Returns value and error of parameter index
350 fitparameters[index] = val ;
359 //____________________________________________________________________________
360 void AliPHOSClusterizerv1::Init()
362 // Make all memory allocations which can not be done in default constructor.
363 // Attach the Clusterizer task to the list of PHOS tasks
365 fEmcCrystals = fGeom->GetNModules() * fGeom->GetNCristalsInModule() ;
368 gMinuit = new TMinuit(100);
371 fgCalibData = new AliPHOSCalibData(-1); //use AliCDBManager's run number
372 if (fgCalibData->GetCalibDataEmc() == 0)
373 AliFatal("Calibration parameters for PHOS EMC not found. Stop reconstruction.\n");
377 //____________________________________________________________________________
378 void AliPHOSClusterizerv1::InitParameters()
381 fNumberOfCpvClusters = 0 ;
382 fNumberOfEmcClusters = 0 ;
384 const AliPHOSRecoParam* parEmc = AliPHOSReconstructor::GetRecoParamEmc();
385 if(!parEmc) AliFatal("Reconstruction parameters for EMC not set!");
387 const AliPHOSRecoParam* parCpv = AliPHOSReconstructor::GetRecoParamCpv();
388 if(!parCpv) AliFatal("Reconstruction parameters for CPV not set!");
390 fCpvClusteringThreshold = parCpv->GetClusteringThreshold();
391 fEmcClusteringThreshold = parEmc->GetClusteringThreshold();
393 fEmcLocMaxCut = parEmc->GetLocalMaxCut();
394 fCpvLocMaxCut = parCpv->GetLocalMaxCut();
396 fW0 = parEmc->GetLogWeight();
397 fW0CPV = parCpv->GetLogWeight();
399 fEmcTimeGate = 1.e-6 ;
401 fToUnfold = parEmc->ToUnfold() ;
406 //____________________________________________________________________________
407 Int_t AliPHOSClusterizerv1::AreNeighbours(AliPHOSDigit * d1, AliPHOSDigit * d2)const
409 // Gives the neighbourness of two digits = 0 are not neighbour but continue searching
411 // = 2 are not neighbour but do not continue searching
412 // =-1 are not neighbour, continue searching, but do not look before d2 next time
413 // neighbours are defined as digits having at least a common vertex
414 // The order of d1 and d2 is important: first (d1) should be a digit already in a cluster
415 // which is compared to a digit (d2) not yet in a cluster
418 fGeom->AbsToRelNumbering(d1->GetId(), relid1) ;
421 fGeom->AbsToRelNumbering(d2->GetId(), relid2) ;
423 if ( (relid1[0] == relid2[0]) && (relid1[1]==relid2[1]) ) { // inside the same PHOS module
424 Int_t rowdiff = TMath::Abs( relid1[2] - relid2[2] ) ;
425 Int_t coldiff = TMath::Abs( relid1[3] - relid2[3] ) ;
427 if (( coldiff <= 1 ) && ( rowdiff <= 1 )){ //At least common vertex
428 // if (( relid1[2]==relid2[2] && coldiff <= 1 ) || ( relid1[3]==relid2[3] && rowdiff <= 1 )){ //common side
429 if((relid1[1] != 0) || (TMath::Abs(d1->GetTime() - d2->GetTime() ) < fEmcTimeGate))
433 if((relid2[2] > relid1[2]) && (relid2[3] > relid1[3]+1))
434 return 2; // Difference in row numbers is too large to look further
440 if(relid1[0] > relid2[0] && relid1[1]==relid2[1] ) //we switched to the next module
442 if(relid1[1] < relid2[1]) //we switched from EMC(0) to CPV(-1)
451 //____________________________________________________________________________
452 Bool_t AliPHOSClusterizerv1::IsInEmc(AliPHOSDigit * digit) const
454 // Tells if (true) or not (false) the digit is in a PHOS-EMC module
458 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
460 if(digit->GetId() <= nEMC ) rv = kTRUE;
465 //____________________________________________________________________________
466 Bool_t AliPHOSClusterizerv1::IsInCpv(AliPHOSDigit * digit) const
468 // Tells if (true) or not (false) the digit is in a PHOS-CPV module
472 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
474 if(digit->GetId() > nEMC ) rv = kTRUE;
479 //____________________________________________________________________________
480 void AliPHOSClusterizerv1::WriteRecPoints()
483 // Creates new branches with given title
484 // fills and writes into TreeR.
487 //Evaluate position, dispersion and other RecPoint properties..
488 Int_t nEmc = fEMCRecPoints->GetEntriesFast();
489 Float_t emcMinE= AliPHOSReconstructor::GetRecoParamEmc()->GetMinE(); //Minimal digit energy
490 for(index = 0; index < nEmc; index++){
491 AliPHOSEmcRecPoint * rp =
492 dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) );
493 rp->Purify(emcMinE) ;
494 if(rp->GetMultiplicity()==0){
495 fEMCRecPoints->RemoveAt(index) ;
500 // No vertex is available now, calculate corrections in PID
501 rp->EvalAll(fW0,fDigitsArr) ;
502 TVector3 fakeVtx(0.,0.,0.) ;
503 rp->EvalAll(fW0,fakeVtx,fDigitsArr) ;
504 rp->EvalLocal2TrackingCSTransform();
506 fEMCRecPoints->Compress() ;
507 fEMCRecPoints->Sort() ;
508 // fEMCRecPoints->Expand(fEMCRecPoints->GetEntriesFast()) ;
509 for(index = 0; index < fEMCRecPoints->GetEntries(); index++){
510 dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) )->SetIndexInList(index) ;
513 //For each rec.point set the distance to the nearest bad crystal (BVP)
514 SetDistancesToBadChannels();
516 //Now the same for CPV
517 for(index = 0; index < fCPVRecPoints->GetEntries(); index++){
518 AliPHOSCpvRecPoint * rp = dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) );
519 rp->EvalAll(fW0CPV,fDigitsArr) ;
520 rp->EvalLocal2TrackingCSTransform();
522 fCPVRecPoints->Sort() ;
524 for(index = 0; index < fCPVRecPoints->GetEntries(); index++)
525 dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) )->SetIndexInList(index) ;
527 fCPVRecPoints->Expand(fCPVRecPoints->GetEntriesFast()) ;
529 if(fWrite){ //We write TreeR
534 //____________________________________________________________________________
535 void AliPHOSClusterizerv1::MakeClusters()
537 // Steering method to construct the clusters stored in a list of Reconstructed Points
538 // A cluster is defined as a list of neighbour digits
540 fNumberOfCpvClusters = 0 ;
541 fNumberOfEmcClusters = 0 ;
543 //Mark all digits as unused yet
544 Int_t nDigits=fDigitsArr->GetEntriesFast() ;
545 for(Int_t i=0; i<nDigits; i++){
548 Int_t iFirst = 0 ; //first index of digit which potentially can be a part of cluster
549 //e.g. first digit in this module, first CPV digit etc.
550 AliPHOSDigit * digit ;
551 TArrayI clusterdigitslist(1500) ;
552 AliPHOSRecPoint * clu = 0 ;
553 for(Int_t i=0; i<nDigits; i++){
557 digit=static_cast<AliPHOSDigit*>(fDigitsArr->At(i)) ;
563 //is this digit so energetic that start cluster?
564 if (( IsInEmc(digit) && digit->GetEnergy() > fEmcClusteringThreshold ) ||
565 ( IsInCpv(digit) && digit->GetEnergy() > fCpvClusteringThreshold ) ) {
566 Int_t iDigitInCluster = 0 ;
568 if ( IsInEmc(digit) ) {
569 // start a new EMC RecPoint
570 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
571 fEMCRecPoints->Expand(2*fNumberOfEmcClusters+1) ;
573 fEMCRecPoints->AddAt(new AliPHOSEmcRecPoint(""), fNumberOfEmcClusters) ;
574 clu = static_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
575 fNumberOfEmcClusters++ ;
576 clu->AddDigit(*digit, digit->GetEnergy()) ;
577 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
579 fDigitsUsed[i]=kTRUE ;
581 // start a new CPV cluster
582 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
583 fCPVRecPoints->Expand(2*fNumberOfCpvClusters+1);
585 fCPVRecPoints->AddAt(new AliPHOSCpvRecPoint(""), fNumberOfCpvClusters) ;
586 clu = static_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
587 fNumberOfCpvClusters++ ;
588 clu->AddDigit(*digit, digit->GetEnergy()) ;
589 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
591 fDigitsUsed[i]=kTRUE ;
594 //Now scan remaining digits in list to find neigbours of our seed
596 AliPHOSDigit * digitN ;
598 while (index < iDigitInCluster){ // scan over digits already in cluster
599 digit = static_cast<AliPHOSDigit*>( fDigitsArr->At(clusterdigitslist[index]) ) ;
601 for(Int_t j=iFirst; j<nDigits; j++){
603 continue ; //look through remaining digits
604 digitN = static_cast<AliPHOSDigit*>( fDigitsArr->At(j) ) ;
605 Int_t ineb = AreNeighbours(digit, digitN); // call (digit,digitN) in THAT oder !!!!!
607 case -1: //too early (e.g. previous module), do not look before j at subsequent passes
610 case 0 : // not a neighbour
612 case 1 : // are neighbours
613 clu->AddDigit(*digitN, digitN->GetEnergy());
614 clusterdigitslist[iDigitInCluster] = j ;
616 fDigitsUsed[j]=kTRUE ;
618 case 2 : // too far from each other
624 endofloop: ; //scanned all possible neighbours for this digit
626 } // loop over cluster
632 //____________________________________________________________________________
633 void AliPHOSClusterizerv1::MakeUnfolding()
635 // Unfolds clusters using the shape of an ElectroMagnetic shower
636 // Performs unfolding of all EMC/CPV clusters
638 // Unfold first EMC clusters
639 if(fNumberOfEmcClusters > 0){
641 Int_t nModulesToUnfold = fGeom->GetNModules() ;
643 Int_t numberofNotUnfolded = fNumberOfEmcClusters ;
645 for(index = 0 ; index < numberofNotUnfolded ; index++){
647 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) ) ;
648 if(emcRecPoint->GetPHOSMod()> nModulesToUnfold)
651 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
652 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
653 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
654 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fEmcLocMaxCut,fDigitsArr) ;
656 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
657 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
659 fEMCRecPoints->Remove(emcRecPoint);
660 fEMCRecPoints->Compress() ;
662 fNumberOfEmcClusters -- ;
663 numberofNotUnfolded-- ;
666 emcRecPoint->SetNExMax(1) ; //Only one local maximum
670 delete[] maxAtEnergy ;
673 // Unfolding of EMC clusters finished
676 // Unfold now CPV clusters
677 if(fNumberOfCpvClusters > 0){
679 Int_t nModulesToUnfold = fGeom->GetNModules() ;
681 Int_t numberofCpvNotUnfolded = fNumberOfCpvClusters ;
683 for(index = 0 ; index < numberofCpvNotUnfolded ; index++){
685 AliPHOSRecPoint * recPoint = dynamic_cast<AliPHOSRecPoint *>( fCPVRecPoints->At(index) ) ;
687 if(recPoint->GetPHOSMod()> nModulesToUnfold)
690 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint*>(recPoint) ;
692 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
693 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
694 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
695 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fCpvLocMaxCut,fDigitsArr) ;
697 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
698 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
699 fCPVRecPoints->Remove(emcRecPoint);
700 fCPVRecPoints->Compress() ;
702 numberofCpvNotUnfolded-- ;
703 fNumberOfCpvClusters-- ;
707 delete[] maxAtEnergy ;
710 //Unfolding of Cpv clusters finished
714 //____________________________________________________________________________
715 Double_t AliPHOSClusterizerv1::ShowerShape(Double_t x, Double_t z)
717 // Shape of the shower (see PHOS TDR)
718 // If you change this function, change also the gradient evaluation in ChiSquare()
720 //for the moment we neglect dependence on the incident angle.
722 Double_t r2 = x*x + z*z ;
723 Double_t r4 = r2*r2 ;
724 Double_t r295 = TMath::Power(r2, 2.95/2.) ;
725 Double_t shape = TMath::Exp( -r4 * (1. / (2.32 + 0.26 * r4) + 0.0316 / (1 + 0.0652 * r295) ) ) ;
729 //____________________________________________________________________________
730 void AliPHOSClusterizerv1::UnfoldCluster(AliPHOSEmcRecPoint * iniEmc,
732 AliPHOSDigit ** maxAt,
733 Float_t * maxAtEnergy)
735 // Performs the unfolding of a cluster with nMax overlapping showers
737 Int_t nPar = 3 * nMax ;
738 Float_t * fitparameters = new Float_t[nPar] ;
740 Bool_t rv = FindFit(iniEmc, maxAt, maxAtEnergy, nPar, fitparameters) ;
743 // Fit failed, return and remove cluster
744 iniEmc->SetNExMax(-1) ;
745 delete[] fitparameters ;
749 // create ufolded rec points and fill them with new energy lists
750 // First calculate energy deposited in each sell in accordance with fit (without fluctuations): efit[]
751 // and later correct this number in acordance with actual energy deposition
753 Int_t nDigits = iniEmc->GetMultiplicity() ;
754 Float_t * efit = new Float_t[nDigits] ;
755 Float_t xDigit=0.,zDigit=0. ;
756 Float_t xpar=0.,zpar=0.,epar=0. ;
758 AliPHOSDigit * digit = 0 ;
759 Int_t * emcDigits = iniEmc->GetDigitsList() ;
765 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
766 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At(emcDigits[iDigit] ) ) ;
767 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
768 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
772 while(iparam < nPar ){
773 xpar = fitparameters[iparam] ;
774 zpar = fitparameters[iparam+1] ;
775 epar = fitparameters[iparam+2] ;
777 // fGeom->GetIncidentVector(fVtx,relid[0],xpar,zpar,vIncid) ;
778 // efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) ;
779 efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
783 // Now create new RecPoints and fill energy lists with efit corrected to fluctuations
784 // so that energy deposited in each cell is distributed betwin new clusters proportionally
785 // to its contribution to efit
787 Float_t * emcEnergies = iniEmc->GetEnergiesList() ;
791 while(iparam < nPar ){
792 xpar = fitparameters[iparam] ;
793 zpar = fitparameters[iparam+1] ;
794 epar = fitparameters[iparam+2] ;
796 // fGeom->GetIncidentVector(fVtx,iniEmc->GetPHOSMod(),xpar,zpar,vIncid) ;
798 AliPHOSEmcRecPoint * emcRP = 0 ;
800 if(iniEmc->IsEmc()){ //create new entries in fEMCRecPoints...
802 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
803 fEMCRecPoints->Expand(2*fNumberOfEmcClusters) ;
805 (*fEMCRecPoints)[fNumberOfEmcClusters] = new AliPHOSEmcRecPoint("") ;
806 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
807 fNumberOfEmcClusters++ ;
808 emcRP->SetNExMax((Int_t)nPar/3) ;
810 else{//create new entries in fCPVRecPoints
811 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
812 fCPVRecPoints->Expand(2*fNumberOfCpvClusters) ;
814 (*fCPVRecPoints)[fNumberOfCpvClusters] = new AliPHOSCpvRecPoint("") ;
815 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
816 fNumberOfCpvClusters++ ;
820 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
821 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At( emcDigits[iDigit] ) ) ;
822 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
823 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
824 // ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) / efit[iDigit] ;
825 ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar) / efit[iDigit] ;
826 eDigit = emcEnergies[iDigit] * ratio ;
827 emcRP->AddDigit( *digit, eDigit ) ;
831 delete[] fitparameters ;
836 //_____________________________________________________________________________
837 void AliPHOSClusterizerv1::UnfoldingChiSquare(Int_t & nPar, Double_t * Grad, Double_t & fret, Double_t * x, Int_t iflag)
839 // Calculates the Chi square for the cluster unfolding minimization
840 // Number of parameters, Gradient, Chi squared, parameters, what to do
842 TList * toMinuit = dynamic_cast<TList*>( gMinuit->GetObjectFit() ) ;
844 AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint*>( toMinuit->At(0) ) ;
845 TClonesArray * digits = dynamic_cast<TClonesArray*>( toMinuit->At(1) ) ;
846 // A bit buggy way to get an access to the geometry
848 AliPHOSGeometry *geom = dynamic_cast<AliPHOSGeometry *>(toMinuit->At(2));
850 // TVector3 * vtx = dynamic_cast<TVector3*>(toMinuit->At(3)) ; //Vertex position
852 // AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( gMinuit->GetObjectFit() ) ; // EmcRecPoint to fit
854 Int_t * emcDigits = emcRP->GetDigitsList() ;
856 Int_t nOdigits = emcRP->GetDigitsMultiplicity() ;
858 Float_t * emcEnergies = emcRP->GetEnergiesList() ;
865 for(iparam = 0 ; iparam < nPar ; iparam++)
866 Grad[iparam] = 0 ; // Will evaluate gradient
870 AliPHOSDigit * digit ;
873 for( iDigit = 0 ; iDigit < nOdigits ; iDigit++) {
875 digit = dynamic_cast<AliPHOSDigit*>( digits->At( emcDigits[iDigit] ) );
881 geom->AbsToRelNumbering(digit->GetId(), relid) ;
883 geom->RelPosInModule(relid, xDigit, zDigit) ;
885 if(iflag == 2){ // calculate gradient
888 while(iParam < nPar ){
889 Double_t dx = (xDigit - x[iParam]) ;
891 Double_t dz = (zDigit - x[iParam]) ;
893 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),x[iParam-2],x[iParam-1],vInc) ;
894 // efit += x[iParam] * ShowerShape(dx,dz,vInc) ;
895 efit += x[iParam] * ShowerShape(dx,dz) ;
898 Double_t sum = 2. * (efit - emcEnergies[iDigit]) / emcEnergies[iDigit] ; // Here we assume, that sigma = sqrt(E)
900 while(iParam < nPar ){
901 Double_t xpar = x[iParam] ;
902 Double_t zpar = x[iParam+1] ;
903 Double_t epar = x[iParam+2] ;
904 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
905 Double_t dr = TMath::Sqrt( (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) );
906 // Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
907 Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar) ;
908 //DP: No incident angle dependence in gradient yet!!!!!!
909 Double_t r4 = dr*dr*dr*dr ;
910 Double_t r295 = TMath::Power(dr,2.95) ;
911 Double_t deriv =-4. * dr*dr * ( 2.32 / ( (2.32 + 0.26 * r4) * (2.32 + 0.26 * r4) ) +
912 0.0316 * (1. + 0.0171 * r295) / ( ( 1. + 0.0652 * r295) * (1. + 0.0652 * r295) ) ) ;
914 Grad[iParam] += epar * shape * deriv * (xpar - xDigit) ; // Derivative over x
916 Grad[iParam] += epar * shape * deriv * (zpar - zDigit) ; // Derivative over z
918 Grad[iParam] += shape ; // Derivative over energy
925 while(iparam < nPar ){
926 Double_t xpar = x[iparam] ;
927 Double_t zpar = x[iparam+1] ;
928 Double_t epar = x[iparam+2] ;
930 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
931 // efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
932 efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
935 fret += (efit-emcEnergies[iDigit])*(efit-emcEnergies[iDigit])/emcEnergies[iDigit] ;
936 // Here we assume, that sigma = sqrt(E)
941 //____________________________________________________________________________
942 void AliPHOSClusterizerv1::Print(const Option_t *)const
944 // Print clusterizer parameters
947 TString taskName(GetName()) ;
948 taskName.ReplaceAll(Version(), "") ;
950 if( strcmp(GetName(), "") !=0 ) {
952 message = "\n--------------- %s %s -----------\n" ;
953 message += "Clusterizing digits from the file: %s\n" ;
954 message += " Branch: %s\n" ;
955 message += " EMC Clustering threshold = %f\n" ;
956 message += " EMC Local Maximum cut = %f\n" ;
957 message += " EMC Logarothmic weight = %f\n" ;
958 message += " CPV Clustering threshold = %f\n" ;
959 message += " CPV Local Maximum cut = %f\n" ;
960 message += " CPV Logarothmic weight = %f\n" ;
962 message += " Unfolding on\n" ;
964 message += " Unfolding off\n" ;
966 message += "------------------------------------------------------------------" ;
969 message = " AliPHOSClusterizerv1 not initialized " ;
971 AliInfo(Form("%s, %s %s %s %s %s %s %s %s %s %s", message.Data(),
976 fEmcClusteringThreshold,
979 fCpvClusteringThreshold,
983 //____________________________________________________________________________
984 void AliPHOSClusterizerv1::PrintRecPoints(Option_t * option)
986 // Prints list of RecPoints produced at the current pass of AliPHOSClusterizer
988 AliInfo(Form("\nFound %d EMC RecPoints and %d CPV RecPoints",
989 fEMCRecPoints->GetEntriesFast(),
990 fCPVRecPoints->GetEntriesFast() )) ;
992 if(strstr(option,"all")) {
993 printf("\n EMC clusters \n") ;
994 printf("Index Ene(MeV) Multi Module X Y Z Lambdas_1 Lambda_2 # of prim Primaries list\n") ;
996 for (index = 0 ; index < fEMCRecPoints->GetEntries() ; index++) {
997 AliPHOSEmcRecPoint * rp = (AliPHOSEmcRecPoint * )fEMCRecPoints->At(index) ;
999 rp->GetLocalPosition(locpos);
1001 rp->GetElipsAxis(lambda);
1004 primaries = rp->GetPrimaries(nprimaries);
1005 printf("\n%6d %8.2f %3d %2d %4.1f %4.1f %4.1f %4f %4f %2d : ",
1006 rp->GetIndexInList(), rp->GetEnergy(), rp->GetMultiplicity(), rp->GetPHOSMod(),
1007 locpos.X(), locpos.Y(), locpos.Z(), lambda[0], lambda[1], nprimaries) ;
1009 for (Int_t iprimary=0; iprimary<nprimaries; iprimary++) {
1010 printf("%d ", primaries[iprimary] ) ;
1015 //Now plot CPV recPoints
1016 printf("\n CPV clusters \n") ;
1017 printf("Index Ene(MeV) Module X Y Z \n") ;
1018 for (index = 0 ; index < fCPVRecPoints->GetEntries() ; index++) {
1019 AliPHOSCpvRecPoint * rp = (AliPHOSCpvRecPoint * )fCPVRecPoints->At(index) ;
1022 rp->GetLocalPosition(locpos);
1024 printf("\n%6d %8.2f %2d %4.1f %4.1f %4.1f \n",
1025 rp->GetIndexInList(), rp->GetEnergy(), rp->GetPHOSMod(),
1026 locpos.X(), locpos.Y(), locpos.Z()) ;
1032 //____________________________________________________________________________
1033 void AliPHOSClusterizerv1::SetDistancesToBadChannels()
1035 //For each EMC rec. point set the distance to the nearest bad crystal.
1036 //Author: Boris Polichtchouk
1038 if(!fgCalibData->GetNumOfEmcBadChannels()) return;
1039 AliInfo(Form("%d bad channel(s) found.\n",fgCalibData->GetNumOfEmcBadChannels()));
1042 fgCalibData->EmcBadChannelIds(badIds);
1044 AliPHOSEmcRecPoint* rp;
1047 TVector3 gposRecPoint; // global (in ALICE frame) position of rec. point
1048 TVector3 gposBadChannel; // global position of bad crystal
1051 Float_t dist,minDist;
1052 Int_t relid[4]={0,0,0,0} ;
1054 for(Int_t iRP=0; iRP<fEMCRecPoints->GetEntries(); iRP++){
1055 rp = (AliPHOSEmcRecPoint*)fEMCRecPoints->At(iRP);
1056 //evaluate distance to border
1057 relid[0]=rp->GetPHOSMod() ;
1060 Float_t xcorner,zcorner;
1061 fGeom->RelPosInModule(relid,xcorner,zcorner) ; //coordinate of the corner cell
1062 rp->GetLocalPosition(lpos) ;
1063 minDist = 2.2+TMath::Min(-xcorner-TMath::Abs(lpos.X()),-zcorner-TMath::Abs(lpos.Z())); //2.2 - crystal size
1064 for(Int_t iBad=0; iBad<fgCalibData->GetNumOfEmcBadChannels(); iBad++) {
1065 fGeom->AbsToRelNumbering(badIds[iBad],relid) ;
1066 if(relid[0]!=rp->GetPHOSMod()) //We can not evaluate global position directly since
1067 continue ; //bad channels can be in the module which does not exist in simulations.
1068 rp->GetGlobalPosition(gposRecPoint,gmat);
1069 fGeom->RelPosInAlice(badIds[iBad],gposBadChannel);
1070 AliDebug(2,Form("BC position:[%.3f,%.3f,%.3f], RP position:[%.3f,%.3f,%.3f]. E=%.3f\n",
1071 gposBadChannel.X(),gposBadChannel.Y(),gposBadChannel.Z(),
1072 gposRecPoint.X(),gposRecPoint.Y(),gposRecPoint.Z(),rp->GetEnergy()));
1073 dR = gposBadChannel-gposRecPoint;
1075 if(dist<minDist) minDist = dist;
1078 rp->SetDistanceToBadCrystal(minDist);