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 "AliCDBManager.h"
184 #include "AliCDBStorage.h"
185 #include "AliCDBEntry.h"
186 #include "AliPHOSRecoParam.h"
187 #include "AliPHOSReconstructor.h"
188 #include "AliPHOSCalibData.h"
190 ClassImp(AliPHOSClusterizerv1)
192 //____________________________________________________________________________
193 AliPHOSClusterizerv1::AliPHOSClusterizerv1() :
194 AliPHOSClusterizer(),
195 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
197 fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
198 fEmcClusteringThreshold(0), fCpvClusteringThreshold(0),
199 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
201 fTimeGateLowAmp(0.), fTimeGateLow(0.), fTimeGateHigh(0.),
204 // 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),
218 fTimeGateLowAmp(0.), fTimeGateLow(0.), fTimeGateHigh(0.),
221 // ctor with the indication of the file where header Tree and digits Tree are stored
224 fDefaultInit = kFALSE ;
227 //____________________________________________________________________________
228 AliPHOSClusterizerv1::~AliPHOSClusterizerv1()
233 //____________________________________________________________________________
234 void AliPHOSClusterizerv1::Digits2Clusters(Option_t *option)
236 // Steering method to perform clusterization for one event
237 // The input is the tree with digits.
238 // The output is the tree with clusters.
240 if(strstr(option,"tim"))
241 gBenchmark->Start("PHOSClusterizer");
243 if(strstr(option,"print")) {
250 AliDebug(2,Form(" ---- Printing clusters (%d)\n",
251 fEMCRecPoints->GetEntries()));
252 if(AliLog::GetGlobalDebugLevel()>1)
253 fEMCRecPoints->Print();
260 if(strstr(option,"deb"))
261 PrintRecPoints(option) ;
263 if(strstr(option,"tim")){
264 gBenchmark->Stop("PHOSClusterizer");
265 AliInfo(Form("took %f seconds for Clusterizing\n",
266 gBenchmark->GetCpuTime("PHOSClusterizer")));
268 fEMCRecPoints->Clear("C");
269 fCPVRecPoints->Clear("C");
272 //____________________________________________________________________________
273 Bool_t AliPHOSClusterizerv1::FindFit(AliPHOSEmcRecPoint * emcRP, AliPHOSDigit ** maxAt, Float_t * maxAtEnergy,
274 Int_t nPar, Float_t * fitparameters) const
276 // Calls TMinuit to fit the energy distribution of a cluster with several maxima
277 // The initial values for fitting procedure are set equal to the positions of local maxima.
278 // Cluster will be fitted as a superposition of nPar/3 electromagnetic showers
281 if(!gMinuit) //it was deleted by someone else
282 gMinuit = new TMinuit(100) ;
283 gMinuit->mncler(); // Reset Minuit's list of paramters
284 gMinuit->SetPrintLevel(-1) ; // No Printout
285 gMinuit->SetFCN(AliPHOSClusterizerv1::UnfoldingChiSquare) ;
286 // To set the address of the minimization function
288 TList * toMinuit = new TList();
289 toMinuit->AddAt(emcRP,0) ;
290 toMinuit->AddAt(fDigitsArr,1) ;
291 toMinuit->AddAt(fGeom,2) ;
293 gMinuit->SetObjectFit(toMinuit) ; // To tranfer pointer to UnfoldingChiSquare
295 // filling initial values for fit parameters
296 AliPHOSDigit * digit ;
300 Int_t nDigits = (Int_t) nPar / 3 ;
304 for(iDigit = 0; iDigit < nDigits; iDigit++){
305 digit = maxAt[iDigit];
310 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
311 fGeom->RelPosInModule(relid, x, z) ;
313 Float_t energy = maxAtEnergy[iDigit] ;
315 gMinuit->mnparm(index, "x", x, 0.1, 0, 0, ierflg) ;
318 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : x = %f\n", x ) ;
321 gMinuit->mnparm(index, "z", z, 0.1, 0, 0, ierflg) ;
324 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : z =%f\n", z ) ;
327 gMinuit->mnparm(index, "Energy", energy , 0.05*energy, 0., 4.*energy, ierflg) ;
330 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : energy = %f\n", energy ) ;
335 Double_t p0 = 0.1 ; // "Tolerance" Evaluation stops when EDM = 0.0001*p0 ; The number of function call slightly
340 gMinuit->mnexcm("SET STR", &p2, 0, ierflg) ; // force TMinuit to reduce function calls
341 gMinuit->mnexcm("SET GRA", &p1, 1, ierflg) ; // force TMinuit to use my gradient
342 gMinuit->SetMaxIterations(5);
343 gMinuit->mnexcm("SET NOW", &p2 , 0, ierflg) ; // No Warnings
345 gMinuit->mnexcm("MIGRAD", &p0, 0, ierflg) ; // minimize
347 if(ierflg == 4){ // Minimum not found
348 Warning("FindFit", "PHOS Unfolding fit not converged, cluster abandoned\n" );
351 for(index = 0; index < nPar; index++){
354 gMinuit->GetParameter(index, val, err) ; // Returns value and error of parameter index
355 fitparameters[index] = val ;
364 //____________________________________________________________________________
365 void AliPHOSClusterizerv1::Init()
367 // Make all memory allocations which can not be done in default constructor.
368 // Attach the Clusterizer task to the list of PHOS tasks
370 fEmcCrystals = fGeom->GetNModules() * fGeom->GetNCristalsInModule() ;
373 gMinuit = new TMinuit(100);
376 fgCalibData = new AliPHOSCalibData(-1); //use AliCDBManager's run number
377 if (fgCalibData->GetCalibDataEmc() == 0)
378 AliFatal("Calibration parameters for PHOS EMC not found. Stop reconstruction.\n");
379 if (fgCalibData->GetCalibDataCpv() == 0)
380 AliFatal("Calibration parameters for PHOS CPV not found. Stop reconstruction.\n");
384 //____________________________________________________________________________
385 void AliPHOSClusterizerv1::InitParameters()
388 fNumberOfCpvClusters = 0 ;
389 fNumberOfEmcClusters = 0 ;
391 const AliPHOSRecoParam* recoParam = AliPHOSReconstructor::GetRecoParam();
392 if(!recoParam) AliFatal("Reconstruction parameters are not set!");
396 fEmcClusteringThreshold = recoParam->GetEMCClusteringThreshold();
397 fCpvClusteringThreshold = recoParam->GetCPVClusteringThreshold();
399 fEmcLocMaxCut = recoParam->GetEMCLocalMaxCut();
400 fCpvLocMaxCut = recoParam->GetCPVLocalMaxCut();
402 fW0 = recoParam->GetEMCLogWeight();
403 fW0CPV = recoParam->GetCPVLogWeight();
405 fTimeGateLowAmp = recoParam->GetTimeGateAmpThresh() ;
406 fTimeGateLow = recoParam->GetTimeGateLow() ;
407 fTimeGateHigh = recoParam->GetTimeGateHigh() ;
409 fEcoreRadius = recoParam->GetEMCEcoreRadius();
411 fToUnfold = recoParam->EMCToUnfold() ;
416 //____________________________________________________________________________
417 Int_t AliPHOSClusterizerv1::AreNeighbours(AliPHOSDigit * d1, AliPHOSDigit * d2)const
419 // Gives the neighbourness of two digits = 0 are not neighbour but continue searching
421 // = 2 are not neighbour but do not continue searching
422 // =-1 are not neighbour, continue searching, but do not look before d2 next time
423 // neighbours are defined as digits having at least a common vertex
424 // The order of d1 and d2 is important: first (d1) should be a digit already in a cluster
425 // which is compared to a digit (d2) not yet in a cluster
428 fGeom->AbsToRelNumbering(d1->GetId(), relid1) ;
431 fGeom->AbsToRelNumbering(d2->GetId(), relid2) ;
433 if ( (relid1[0] == relid2[0]) && (relid1[1]==relid2[1]) ) { // inside the same PHOS module
434 Int_t rowdiff = TMath::Abs( relid1[2] - relid2[2] ) ;
435 Int_t coldiff = TMath::Abs( relid1[3] - relid2[3] ) ;
437 if (( coldiff <= 1 ) && ( rowdiff <= 1 )){ //At least common vertex
438 // if (( relid1[2]==relid2[2] && coldiff <= 1 ) || ( relid1[3]==relid2[3] && rowdiff <= 1 )){ //common side
439 if((relid1[1] != 0) || CheckTimeGate(d1->GetTime(),d1->GetEnergy(),d2->GetTime(),d2->GetEnergy()))
443 if((relid2[2] > relid1[2]) && (relid2[3] > relid1[3]+1))
444 return 2; // Difference in row numbers is too large to look further
450 if(relid1[0] > relid2[0] && relid1[1]==relid2[1] ) //we switched to the next module
452 if(relid1[1] < relid2[1]) //we switched from EMC(0) to CPV(-1)
461 //____________________________________________________________________________
462 Bool_t AliPHOSClusterizerv1::CheckTimeGate(Float_t t1, Float_t amp1, Float_t t2, Float_t amp2)const{
463 //Check if two cells have reasonable time difference
464 //Note that at low amplitude time is defined up to 1 tick == 100 ns.
465 if(amp1<fTimeGateLowAmp || amp2<fTimeGateLowAmp){
466 return (TMath::Abs(t1 - t2 ) < fTimeGateLow) ;
468 else{ //Time should be measured with good accuracy
469 return (TMath::Abs(t1 - t2 ) < fTimeGateHigh) ;
473 //____________________________________________________________________________
474 Bool_t AliPHOSClusterizerv1::IsInEmc(AliPHOSDigit * digit) const
476 // Tells if (true) or not (false) the digit is in a PHOS-EMC module
480 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
482 if(digit->GetId() <= nEMC ) rv = kTRUE;
487 //____________________________________________________________________________
488 Bool_t AliPHOSClusterizerv1::IsInCpv(AliPHOSDigit * digit) const
490 // Tells if (true) or not (false) the digit is in a PHOS-CPV module
494 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
496 if(digit->GetId() > nEMC ) rv = kTRUE;
501 //____________________________________________________________________________
502 void AliPHOSClusterizerv1::WriteRecPoints()
505 // Creates new branches with given title
506 // fills and writes into TreeR.
509 //Evaluate position, dispersion and other RecPoint properties..
510 Int_t nEmc = fEMCRecPoints->GetEntriesFast();
511 Float_t emcMinE= AliPHOSReconstructor::GetRecoParam()->GetEMCMinE(); //Minimal digit energy
512 TVector3 fakeVtx(0.,0.,0.) ;
513 for(index = 0; index < nEmc; index++){
514 AliPHOSEmcRecPoint * rp =
515 dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) );
516 rp->Purify(emcMinE) ;
517 if(rp->GetMultiplicity()==0){
518 fEMCRecPoints->RemoveAt(index) ;
523 // No vertex is available now, calculate corrections in PID
524 rp->EvalAll(fDigitsArr) ;
525 rp->EvalCoreEnergy(fW0,fEcoreRadius,fDigitsArr) ;
526 rp->EvalAll(fW0,fakeVtx,fDigitsArr) ;
527 rp->EvalLocal2TrackingCSTransform();
529 fEMCRecPoints->Compress() ;
530 fEMCRecPoints->Sort() ;
531 // fEMCRecPoints->Expand(fEMCRecPoints->GetEntriesFast()) ;
532 for(index = 0; index < fEMCRecPoints->GetEntries(); index++){
533 dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) )->SetIndexInList(index) ;
536 //For each rec.point set the distance to the nearest bad crystal (BVP)
537 SetDistancesToBadChannels();
539 //Now the same for CPV
540 for(index = 0; index < fCPVRecPoints->GetEntries(); index++){
541 AliPHOSCpvRecPoint * rp = dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) );
542 rp->EvalAll(fDigitsArr) ;
543 rp->EvalAll(fW0CPV,fakeVtx,fDigitsArr) ;
544 rp->EvalLocal2TrackingCSTransform();
546 fCPVRecPoints->Sort() ;
548 for(index = 0; index < fCPVRecPoints->GetEntries(); index++)
549 dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) )->SetIndexInList(index) ;
551 fCPVRecPoints->Expand(fCPVRecPoints->GetEntriesFast()) ;
553 if(fWrite){ //We write TreeR
558 //____________________________________________________________________________
559 void AliPHOSClusterizerv1::MakeClusters()
561 // Steering method to construct the clusters stored in a list of Reconstructed Points
562 // A cluster is defined as a list of neighbour digits
564 fNumberOfCpvClusters = 0 ;
565 fNumberOfEmcClusters = 0 ;
567 //Mark all digits as unused yet
568 const Int_t maxNDigits = 3584; // There is no clusters larger than PHOS module ;)
569 Int_t nDigits=fDigitsArr->GetEntriesFast() ;
571 for(Int_t i=0; i<nDigits; i++){
574 Int_t iFirst = 0 ; //first index of digit which potentially can be a part of cluster
575 //e.g. first digit in this module, first CPV digit etc.
576 AliPHOSDigit * digit ;
577 TArrayI clusterdigitslist(maxNDigits) ;
578 AliPHOSRecPoint * clu = 0 ;
579 for(Int_t i=0; i<nDigits; i++){
583 digit=static_cast<AliPHOSDigit*>(fDigitsArr->At(i)) ;
589 //is this digit so energetic that start cluster?
590 if (( IsInEmc(digit) && Calibrate(digit->GetEnergy(),digit->GetId()) > fEmcClusteringThreshold ) ||
591 ( IsInCpv(digit) && Calibrate(digit->GetEnergy(),digit->GetId()) > fCpvClusteringThreshold ) ) {
592 Int_t iDigitInCluster = 0 ;
593 if ( IsInEmc(digit) ) {
594 // start a new EMC RecPoint
595 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
596 fEMCRecPoints->Expand(2*fNumberOfEmcClusters+1) ;
598 fEMCRecPoints->AddAt(new AliPHOSEmcRecPoint(""), fNumberOfEmcClusters) ;
599 clu = static_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
600 fNumberOfEmcClusters++ ;
601 clu->AddDigit(*digit, Calibrate(digit->GetEnergy(),digit->GetId()),CalibrateT(digit->GetTime(),digit->GetId())) ;
602 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
604 fDigitsUsed[i]=kTRUE ;
606 // start a new CPV cluster
607 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
608 fCPVRecPoints->Expand(2*fNumberOfCpvClusters+1);
610 fCPVRecPoints->AddAt(new AliPHOSCpvRecPoint(""), fNumberOfCpvClusters) ;
611 clu = static_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
612 fNumberOfCpvClusters++ ;
613 clu->AddDigit(*digit, Calibrate(digit->GetEnergy(),digit->GetId()),0.) ; // no timing information in CPV
614 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
616 fDigitsUsed[i]=kTRUE ;
619 //Now scan remaining digits in list to find neigbours of our seed
621 AliPHOSDigit * digitN ;
623 while (index < iDigitInCluster){ // scan over digits already in cluster
624 digit = static_cast<AliPHOSDigit*>( fDigitsArr->At(clusterdigitslist[index]) ) ;
626 for(Int_t j=iFirst; j<nDigits; j++){
627 if (iDigitInCluster >= maxNDigits) {
628 AliError(Form("The number of digits in cluster is more than %d, skip the rest of event",
633 continue ; //look through remaining digits
634 digitN = static_cast<AliPHOSDigit*>( fDigitsArr->At(j) ) ;
635 Int_t ineb = AreNeighbours(digit, digitN); // call (digit,digitN) in THAT oder !!!!!
637 case -1: //too early (e.g. previous module), do not look before j at subsequent passes
640 case 0 : // not a neighbour
642 case 1 : // are neighbours
643 clu->AddDigit(*digitN, Calibrate(digitN->GetEnergy(),digitN->GetId()),CalibrateT(digitN->GetTime(),digitN->GetId())) ;
644 clusterdigitslist[iDigitInCluster] = j ;
646 fDigitsUsed[j]=kTRUE ;
648 case 2 : // too far from each other
654 endOfLoop: ; //scanned all possible neighbours for this digit
656 } // loop over cluster
662 //____________________________________________________________________________
663 void AliPHOSClusterizerv1::MakeUnfolding()
665 // Unfolds clusters using the shape of an ElectroMagnetic shower
666 // Performs unfolding of all EMC/CPV clusters
668 // Unfold first EMC clusters
669 if(fNumberOfEmcClusters > 0){
671 Int_t nModulesToUnfold = fGeom->GetNModules() ;
673 Int_t numberofNotUnfolded = fNumberOfEmcClusters ;
675 for(index = 0 ; index < numberofNotUnfolded ; index++){
677 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) ) ;
678 if(emcRecPoint->GetPHOSMod()> nModulesToUnfold)
681 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
682 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
683 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
684 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fEmcLocMaxCut,fDigitsArr) ;
686 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
687 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
689 fEMCRecPoints->Remove(emcRecPoint);
690 fEMCRecPoints->Compress() ;
692 fNumberOfEmcClusters -- ;
693 numberofNotUnfolded-- ;
696 emcRecPoint->SetNExMax(1) ; //Only one local maximum
700 delete[] maxAtEnergy ;
703 // Unfolding of EMC clusters finished
706 // Unfold now CPV clusters
707 if(fNumberOfCpvClusters > 0){
709 Int_t nModulesToUnfold = fGeom->GetNModules() ;
711 Int_t numberofCpvNotUnfolded = fNumberOfCpvClusters ;
713 for(index = 0 ; index < numberofCpvNotUnfolded ; index++){
715 AliPHOSRecPoint * recPoint = dynamic_cast<AliPHOSRecPoint *>( fCPVRecPoints->At(index) ) ;
717 if(recPoint->GetPHOSMod()> nModulesToUnfold)
720 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint*>(recPoint) ;
722 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
723 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
724 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
725 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fCpvLocMaxCut,fDigitsArr) ;
727 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
728 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
729 fCPVRecPoints->Remove(emcRecPoint);
730 fCPVRecPoints->Compress() ;
732 numberofCpvNotUnfolded-- ;
733 fNumberOfCpvClusters-- ;
737 delete[] maxAtEnergy ;
740 //Unfolding of Cpv clusters finished
744 //____________________________________________________________________________
745 Double_t AliPHOSClusterizerv1::ShowerShape(Double_t x, Double_t z)
747 // Shape of the shower (see PHOS TDR)
748 // If you change this function, change also the gradient evaluation in ChiSquare()
750 //for the moment we neglect dependence on the incident angle.
752 Double_t r2 = x*x + z*z ;
753 Double_t r4 = r2*r2 ;
754 Double_t r295 = TMath::Power(r2, 2.95/2.) ;
755 Double_t shape = TMath::Exp( -r4 * (1. / (2.32 + 0.26 * r4) + 0.0316 / (1 + 0.0652 * r295) ) ) ;
759 //____________________________________________________________________________
760 void AliPHOSClusterizerv1::UnfoldCluster(AliPHOSEmcRecPoint * iniEmc,
762 AliPHOSDigit ** maxAt,
763 Float_t * maxAtEnergy)
765 // Performs the unfolding of a cluster with nMax overlapping showers
767 Int_t nPar = 3 * nMax ;
768 Float_t * fitparameters = new Float_t[nPar] ;
770 Bool_t rv = FindFit(iniEmc, maxAt, maxAtEnergy, nPar, fitparameters) ;
773 // Fit failed, return and remove cluster
774 iniEmc->SetNExMax(-1) ;
775 delete[] fitparameters ;
779 // create ufolded rec points and fill them with new energy lists
780 // First calculate energy deposited in each sell in accordance with fit (without fluctuations): efit[]
781 // and later correct this number in acordance with actual energy deposition
783 Int_t nDigits = iniEmc->GetMultiplicity() ;
784 Float_t * efit = new Float_t[nDigits] ;
785 Float_t xDigit=0.,zDigit=0. ;
786 Float_t xpar=0.,zpar=0.,epar=0. ;
788 AliPHOSDigit * digit = 0 ;
789 Int_t * emcDigits = iniEmc->GetDigitsList() ;
795 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
796 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At(emcDigits[iDigit] ) ) ;
797 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
798 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
802 while(iparam < nPar ){
803 xpar = fitparameters[iparam] ;
804 zpar = fitparameters[iparam+1] ;
805 epar = fitparameters[iparam+2] ;
807 // fGeom->GetIncidentVector(fVtx,relid[0],xpar,zpar,vIncid) ;
808 // efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) ;
809 efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
813 // Now create new RecPoints and fill energy lists with efit corrected to fluctuations
814 // so that energy deposited in each cell is distributed betwin new clusters proportionally
815 // to its contribution to efit
817 Float_t * emcEnergies = iniEmc->GetEnergiesList() ;
821 while(iparam < nPar ){
822 xpar = fitparameters[iparam] ;
823 zpar = fitparameters[iparam+1] ;
824 epar = fitparameters[iparam+2] ;
826 // fGeom->GetIncidentVector(fVtx,iniEmc->GetPHOSMod(),xpar,zpar,vIncid) ;
828 AliPHOSEmcRecPoint * emcRP = 0 ;
830 if(iniEmc->IsEmc()){ //create new entries in fEMCRecPoints...
832 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
833 fEMCRecPoints->Expand(2*fNumberOfEmcClusters) ;
835 (*fEMCRecPoints)[fNumberOfEmcClusters] = new AliPHOSEmcRecPoint("") ;
836 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
837 fNumberOfEmcClusters++ ;
838 emcRP->SetNExMax((Int_t)nPar/3) ;
840 else{//create new entries in fCPVRecPoints
841 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
842 fCPVRecPoints->Expand(2*fNumberOfCpvClusters) ;
844 (*fCPVRecPoints)[fNumberOfCpvClusters] = new AliPHOSCpvRecPoint("") ;
845 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
846 fNumberOfCpvClusters++ ;
850 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
851 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At( emcDigits[iDigit] ) ) ;
852 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
853 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
854 // ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) / efit[iDigit] ;
855 ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar) / efit[iDigit] ;
856 eDigit = emcEnergies[iDigit] * ratio ;
857 emcRP->AddDigit( *digit, eDigit,CalibrateT(digit->GetTime(),digit->GetId()) ) ;
861 delete[] fitparameters ;
866 //_____________________________________________________________________________
867 void AliPHOSClusterizerv1::UnfoldingChiSquare(Int_t & nPar, Double_t * Grad, Double_t & fret, Double_t * x, Int_t iflag)
869 // Calculates the Chi square for the cluster unfolding minimization
870 // Number of parameters, Gradient, Chi squared, parameters, what to do
872 TList * toMinuit = dynamic_cast<TList*>( gMinuit->GetObjectFit() ) ;
874 AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint*>( toMinuit->At(0) ) ;
875 TClonesArray * digits = dynamic_cast<TClonesArray*>( toMinuit->At(1) ) ;
876 // A bit buggy way to get an access to the geometry
878 AliPHOSGeometry *geom = dynamic_cast<AliPHOSGeometry *>(toMinuit->At(2));
880 // TVector3 * vtx = dynamic_cast<TVector3*>(toMinuit->At(3)) ; //Vertex position
882 // AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( gMinuit->GetObjectFit() ) ; // EmcRecPoint to fit
884 Int_t * emcDigits = emcRP->GetDigitsList() ;
886 Int_t nOdigits = emcRP->GetDigitsMultiplicity() ;
888 Float_t * emcEnergies = emcRP->GetEnergiesList() ;
895 for(iparam = 0 ; iparam < nPar ; iparam++)
896 Grad[iparam] = 0 ; // Will evaluate gradient
900 AliPHOSDigit * digit ;
903 for( iDigit = 0 ; iDigit < nOdigits ; iDigit++) {
905 digit = dynamic_cast<AliPHOSDigit*>( digits->At( emcDigits[iDigit] ) );
911 geom->AbsToRelNumbering(digit->GetId(), relid) ;
913 geom->RelPosInModule(relid, xDigit, zDigit) ;
915 if(iflag == 2){ // calculate gradient
918 while(iParam < nPar ){
919 Double_t dx = (xDigit - x[iParam]) ;
921 Double_t dz = (zDigit - x[iParam]) ;
923 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),x[iParam-2],x[iParam-1],vInc) ;
924 // efit += x[iParam] * ShowerShape(dx,dz,vInc) ;
925 efit += x[iParam] * ShowerShape(dx,dz) ;
928 Double_t sum = 2. * (efit - emcEnergies[iDigit]) / emcEnergies[iDigit] ; // Here we assume, that sigma = sqrt(E)
930 while(iParam < nPar ){
931 Double_t xpar = x[iParam] ;
932 Double_t zpar = x[iParam+1] ;
933 Double_t epar = x[iParam+2] ;
934 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
935 Double_t dr = TMath::Sqrt( (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) );
936 // Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
937 Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar) ;
938 //DP: No incident angle dependence in gradient yet!!!!!!
939 Double_t r4 = dr*dr*dr*dr ;
940 Double_t r295 = TMath::Power(dr,2.95) ;
941 Double_t deriv =-4. * dr*dr * ( 2.32 / ( (2.32 + 0.26 * r4) * (2.32 + 0.26 * r4) ) +
942 0.0316 * (1. + 0.0171 * r295) / ( ( 1. + 0.0652 * r295) * (1. + 0.0652 * r295) ) ) ;
944 Grad[iParam] += epar * shape * deriv * (xpar - xDigit) ; // Derivative over x
946 Grad[iParam] += epar * shape * deriv * (zpar - zDigit) ; // Derivative over z
948 Grad[iParam] += shape ; // Derivative over energy
955 while(iparam < nPar ){
956 Double_t xpar = x[iparam] ;
957 Double_t zpar = x[iparam+1] ;
958 Double_t epar = x[iparam+2] ;
960 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
961 // efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
962 efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
965 fret += (efit-emcEnergies[iDigit])*(efit-emcEnergies[iDigit])/emcEnergies[iDigit] ;
966 // Here we assume, that sigma = sqrt(E)
971 //____________________________________________________________________________
972 void AliPHOSClusterizerv1::Print(const Option_t *)const
974 // Print clusterizer parameters
977 TString taskName(GetName()) ;
978 taskName.ReplaceAll(Version(), "") ;
980 if( strcmp(GetName(), "") !=0 ) {
982 message = "\n--------------- %s %s -----------\n" ;
983 message += "Clusterizing digits from the file: %s\n" ;
984 message += " Branch: %s\n" ;
985 message += " EMC Clustering threshold = %f\n" ;
986 message += " EMC Local Maximum cut = %f\n" ;
987 message += " EMC Logarothmic weight = %f\n" ;
988 message += " CPV Clustering threshold = %f\n" ;
989 message += " CPV Local Maximum cut = %f\n" ;
990 message += " CPV Logarothmic weight = %f\n" ;
992 message += " Unfolding on\n" ;
994 message += " Unfolding off\n" ;
996 message += "------------------------------------------------------------------" ;
999 message = " AliPHOSClusterizerv1 not initialized " ;
1001 AliInfo(Form("%s, %s %s %s %s %f %f %f %f %f %f", message.Data(),
1006 fEmcClusteringThreshold,
1009 fCpvClusteringThreshold,
1013 //____________________________________________________________________________
1014 void AliPHOSClusterizerv1::PrintRecPoints(Option_t * option)
1016 // Prints list of RecPoints produced at the current pass of AliPHOSClusterizer
1018 AliInfo(Form("\nFound %d EMC RecPoints and %d CPV RecPoints",
1019 fEMCRecPoints->GetEntriesFast(),
1020 fCPVRecPoints->GetEntriesFast() )) ;
1022 if(strstr(option,"all")) {
1023 printf("\n EMC clusters \n") ;
1024 printf("Index Ene(MeV) Multi Module X Y Z Lambdas_1 Lambda_2 # of prim Primaries list\n") ;
1026 for (index = 0 ; index < fEMCRecPoints->GetEntries() ; index++) {
1027 AliPHOSEmcRecPoint * rp = (AliPHOSEmcRecPoint * )fEMCRecPoints->At(index) ;
1029 rp->GetLocalPosition(locpos);
1031 rp->GetElipsAxis(lambda);
1034 primaries = rp->GetPrimaries(nprimaries);
1035 printf("\n%6d %8.2f %3d %2d %4.1f %4.1f %4.1f %4f %4f %2d : ",
1036 rp->GetIndexInList(), rp->GetEnergy(), rp->GetMultiplicity(), rp->GetPHOSMod(),
1037 locpos.X(), locpos.Y(), locpos.Z(), lambda[0], lambda[1], nprimaries) ;
1039 for (Int_t iprimary=0; iprimary<nprimaries; iprimary++) {
1040 printf("%d ", primaries[iprimary] ) ;
1045 //Now plot CPV recPoints
1046 printf("\n CPV clusters \n") ;
1047 printf("Index Ene(MeV) Module X Y Z \n") ;
1048 for (index = 0 ; index < fCPVRecPoints->GetEntries() ; index++) {
1049 AliPHOSCpvRecPoint * rp = (AliPHOSCpvRecPoint * )fCPVRecPoints->At(index) ;
1052 rp->GetLocalPosition(locpos);
1054 printf("\n%6d %8.2f %2d %4.1f %4.1f %4.1f \n",
1055 rp->GetIndexInList(), rp->GetEnergy(), rp->GetPHOSMod(),
1056 locpos.X(), locpos.Y(), locpos.Z()) ;
1062 //____________________________________________________________________________
1063 void AliPHOSClusterizerv1::SetDistancesToBadChannels()
1065 //For each EMC rec. point set the distance to the nearest bad crystal.
1066 //Author: Boris Polichtchouk
1068 if(!fgCalibData->GetNumOfEmcBadChannels()) return;
1071 memset(badIds,0,8000*sizeof(Int_t));
1072 fgCalibData->EmcBadChannelIds(badIds);
1074 AliPHOSEmcRecPoint* rp;
1077 TVector3 gposRecPoint; // global (in ALICE frame) position of rec. point
1078 TVector3 gposBadChannel; // global position of bad crystal
1081 Float_t dist,minDist;
1082 Int_t relid[4]={0,0,0,0} ;
1084 for(Int_t iRP=0; iRP<fEMCRecPoints->GetEntries(); iRP++){
1085 rp = (AliPHOSEmcRecPoint*)fEMCRecPoints->At(iRP);
1086 //evaluate distance to border
1087 relid[0]=rp->GetPHOSMod() ;
1090 Float_t xcorner,zcorner;
1091 fGeom->RelPosInModule(relid,xcorner,zcorner) ; //coordinate of the corner cell
1092 rp->GetLocalPosition(lpos) ;
1093 minDist = 2.2+TMath::Min(-xcorner-TMath::Abs(lpos.X()),-zcorner-TMath::Abs(lpos.Z())); //2.2 - crystal size
1094 for(Int_t iBad=0; iBad<fgCalibData->GetNumOfEmcBadChannels(); iBad++) {
1095 fGeom->AbsToRelNumbering(badIds[iBad],relid) ;
1096 if(relid[0]!=rp->GetPHOSMod()) //We can not evaluate global position directly since
1097 continue ; //bad channels can be in the module which does not exist in simulations.
1098 rp->GetGlobalPosition(gposRecPoint,gmat);
1099 fGeom->RelPosInAlice(badIds[iBad],gposBadChannel);
1100 AliDebug(2,Form("BC position:[%.3f,%.3f,%.3f], RP position:[%.3f,%.3f,%.3f]. E=%.3f\n",
1101 gposBadChannel.X(),gposBadChannel.Y(),gposBadChannel.Z(),
1102 gposRecPoint.X(),gposRecPoint.Y(),gposRecPoint.Z(),rp->GetEnergy()));
1103 dR = gposBadChannel-gposRecPoint;
1105 if(dist<minDist) minDist = dist;
1108 rp->SetDistanceToBadCrystal(minDist);
1112 //==================================================================================
1113 Float_t AliPHOSClusterizerv1::Calibrate(Float_t amp, Int_t absId) const{
1114 // Calibrate EMC digit, i.e. multiply its Amp by a factor read from CDB
1116 const AliPHOSGeometry *geom = AliPHOSGeometry::GetInstance() ;
1118 //Determine rel.position of the cell absolute ID
1120 geom->AbsToRelNumbering(absId,relId);
1121 Int_t module=relId[0];
1122 Int_t row =relId[2];
1123 Int_t column=relId[3];
1125 Float_t calibration = fgCalibData->GetADCchannelCpv(module,column,row);
1126 return amp*calibration ;
1129 Float_t calibration = fgCalibData->GetADCchannelEmc(module,column,row);
1130 return amp*calibration ;
1133 //==================================================================================
1134 Float_t AliPHOSClusterizerv1::CalibrateT(Float_t time, Int_t absId)const{
1135 // Calibrate time in EMC digit
1137 const AliPHOSGeometry *geom = AliPHOSGeometry::GetInstance() ;
1139 //Determine rel.position of the cell absolute ID
1141 geom->AbsToRelNumbering(absId,relId);
1142 Int_t module=relId[0];
1143 Int_t row =relId[2];
1144 Int_t column=relId[3];
1149 time += fgCalibData->GetTimeShiftEmc(module,column,row);