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 ;
208 for(Int_t i=0; i<53760; i++){
213 //____________________________________________________________________________
214 AliPHOSClusterizerv1::AliPHOSClusterizerv1(AliPHOSGeometry *geom) :
215 AliPHOSClusterizer(geom),
216 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
218 fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
219 fEmcClusteringThreshold(0), fCpvClusteringThreshold(0),
220 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
222 fTimeGateLowAmp(0.), fTimeGateLow(0.), fTimeGateHigh(0.),
225 // ctor with the indication of the file where header Tree and digits Tree are stored
227 for(Int_t i=0; i<53760; i++){
232 fDefaultInit = kFALSE ;
235 //____________________________________________________________________________
236 AliPHOSClusterizerv1::~AliPHOSClusterizerv1()
241 //____________________________________________________________________________
242 void AliPHOSClusterizerv1::Digits2Clusters(Option_t *option)
244 // Steering method to perform clusterization for one event
245 // The input is the tree with digits.
246 // The output is the tree with clusters.
248 if(strstr(option,"tim"))
249 gBenchmark->Start("PHOSClusterizer");
251 if(strstr(option,"print")) {
258 AliDebug(2,Form("Number of EMC clusters: %d, CPV clusters: %d\n",
259 fEMCRecPoints->GetEntriesFast(), fCPVRecPoints->GetEntriesFast()));
260 if(AliLog::GetGlobalDebugLevel()>1) {
261 fEMCRecPoints->Print();
262 fCPVRecPoints->Print();
270 if(strstr(option,"deb"))
271 PrintRecPoints(option) ;
273 if(strstr(option,"tim")){
274 gBenchmark->Stop("PHOSClusterizer");
275 AliInfo(Form("took %f seconds for Clusterizing\n",
276 gBenchmark->GetCpuTime("PHOSClusterizer")));
278 fEMCRecPoints->Delete();
279 fCPVRecPoints->Delete();
282 //____________________________________________________________________________
283 Bool_t AliPHOSClusterizerv1::FindFit(AliPHOSEmcRecPoint * emcRP, AliPHOSDigit ** maxAt, Float_t * maxAtEnergy,
284 Int_t nPar, Float_t * fitparameters) const
286 // Calls TMinuit to fit the energy distribution of a cluster with several maxima
287 // The initial values for fitting procedure are set equal to the positions of local maxima.
288 // Cluster will be fitted as a superposition of nPar/3 electromagnetic showers
291 if(!gMinuit) //it was deleted by someone else
292 gMinuit = new TMinuit(100) ;
293 gMinuit->mncler(); // Reset Minuit's list of paramters
294 gMinuit->SetPrintLevel(-1) ; // No Printout
295 gMinuit->SetFCN(AliPHOSClusterizerv1::UnfoldingChiSquare) ;
296 // To set the address of the minimization function
298 TList * toMinuit = new TList();
299 toMinuit->AddAt(emcRP,0) ;
300 toMinuit->AddAt(fDigitsArr,1) ;
301 toMinuit->AddAt(fGeom,2) ;
303 gMinuit->SetObjectFit(toMinuit) ; // To tranfer pointer to UnfoldingChiSquare
305 // filling initial values for fit parameters
306 AliPHOSDigit * digit ;
310 Int_t nDigits = (Int_t) nPar / 3 ;
314 for(iDigit = 0; iDigit < nDigits; iDigit++){
315 digit = maxAt[iDigit];
320 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
321 fGeom->RelPosInModule(relid, x, z) ;
323 Float_t energy = maxAtEnergy[iDigit] ;
325 gMinuit->mnparm(index, "x", x, 0.1, 0, 0, ierflg) ;
328 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : x = %f\n", x ) ;
331 gMinuit->mnparm(index, "z", z, 0.1, 0, 0, ierflg) ;
334 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : z =%f\n", z ) ;
337 gMinuit->mnparm(index, "Energy", energy , 0.05*energy, 0., 4.*energy, ierflg) ;
340 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : energy = %f\n", energy ) ;
345 Double_t p0 = 0.1 ; // "Tolerance" Evaluation stops when EDM = 0.0001*p0 ; The number of function call slightly
350 gMinuit->mnexcm("SET STR", &p2, 0, ierflg) ; // force TMinuit to reduce function calls
351 gMinuit->mnexcm("SET GRA", &p1, 1, ierflg) ; // force TMinuit to use my gradient
352 gMinuit->SetMaxIterations(5);
353 gMinuit->mnexcm("SET NOW", &p2 , 0, ierflg) ; // No Warnings
355 gMinuit->mnexcm("MIGRAD", &p0, 0, ierflg) ; // minimize
357 if(ierflg == 4){ // Minimum not found
358 Warning("FindFit", "PHOS Unfolding fit not converged, cluster abandoned\n" );
361 for(index = 0; index < nPar; index++){
364 gMinuit->GetParameter(index, val, err) ; // Returns value and error of parameter index
365 fitparameters[index] = val ;
374 //____________________________________________________________________________
375 void AliPHOSClusterizerv1::Init()
377 // Make all memory allocations which can not be done in default constructor.
378 // Attach the Clusterizer task to the list of PHOS tasks
380 fEmcCrystals = fGeom->GetNModules() * fGeom->GetNCristalsInModule() ;
383 gMinuit = new TMinuit(100);
386 fgCalibData = new AliPHOSCalibData(-1); //use AliCDBManager's run number
387 if (fgCalibData->GetCalibDataEmc() == 0)
388 AliFatal("Calibration parameters for PHOS EMC not found. Stop reconstruction.\n");
389 if (fgCalibData->GetCalibDataCpv() == 0)
390 AliFatal("Calibration parameters for PHOS CPV not found. Stop reconstruction.\n");
394 //____________________________________________________________________________
395 void AliPHOSClusterizerv1::InitParameters()
398 fNumberOfCpvClusters = 0 ;
399 fNumberOfEmcClusters = 0 ;
401 const AliPHOSRecoParam* recoParam = AliPHOSReconstructor::GetRecoParam();
402 if(!recoParam) AliFatal("Reconstruction parameters are not set!");
406 fEmcClusteringThreshold = recoParam->GetEMCClusteringThreshold();
407 fCpvClusteringThreshold = recoParam->GetCPVClusteringThreshold();
409 fEmcLocMaxCut = recoParam->GetEMCLocalMaxCut();
410 fCpvLocMaxCut = recoParam->GetCPVLocalMaxCut();
412 fW0 = recoParam->GetEMCLogWeight();
413 fW0CPV = recoParam->GetCPVLogWeight();
415 fTimeGateLowAmp = recoParam->GetTimeGateAmpThresh() ;
416 fTimeGateLow = recoParam->GetTimeGateLow() ;
417 fTimeGateHigh = recoParam->GetTimeGateHigh() ;
419 fEcoreRadius = recoParam->GetEMCEcoreRadius();
421 fToUnfold = recoParam->EMCToUnfold() ;
426 //____________________________________________________________________________
427 Int_t AliPHOSClusterizerv1::AreNeighbours(AliPHOSDigit * d1, AliPHOSDigit * d2)const
429 // Gives the neighbourness of two digits = 0 are not neighbour but continue searching
431 // = 2 are not neighbour but do not continue searching
432 // =-1 are not neighbour, continue searching, but do not look before d2 next time
433 // neighbours are defined as digits having at least a common vertex
434 // The order of d1 and d2 is important: first (d1) should be a digit already in a cluster
435 // which is compared to a digit (d2) not yet in a cluster
438 fGeom->AbsToRelNumbering(d1->GetId(), relid1) ;
441 fGeom->AbsToRelNumbering(d2->GetId(), relid2) ;
443 if ( (relid1[0] == relid2[0]) && (relid1[1]==relid2[1]) ) { // inside the same PHOS module
444 Int_t rowdiff = TMath::Abs( relid1[2] - relid2[2] ) ;
445 Int_t coldiff = TMath::Abs( relid1[3] - relid2[3] ) ;
447 if (( coldiff <= 1 ) && ( rowdiff <= 1 )){ //At least common vertex
448 // if (( relid1[2]==relid2[2] && coldiff <= 1 ) || ( relid1[3]==relid2[3] && rowdiff <= 1 )){ //common side
449 if((relid1[1] != 0) || CheckTimeGate(d1->GetTime(),d1->GetEnergy(),d2->GetTime(),d2->GetEnergy()))
453 if((relid2[2] > relid1[2]) && (relid2[3] > relid1[3]+1))
454 return 2; // Difference in row numbers is too large to look further
460 if(relid1[0] > relid2[0] && relid1[1]==relid2[1] ) //we switched to the next module
462 if(relid1[1] < relid2[1]) //we switched from EMC(0) to CPV(-1)
471 //____________________________________________________________________________
472 Bool_t AliPHOSClusterizerv1::CheckTimeGate(Float_t t1, Float_t amp1, Float_t t2, Float_t amp2)const{
473 //Check if two cells have reasonable time difference
474 //Note that at low amplitude time is defined up to 1 tick == 100 ns.
475 if(amp1<fTimeGateLowAmp || amp2<fTimeGateLowAmp){
476 return (TMath::Abs(t1 - t2 ) < fTimeGateLow) ;
478 else{ //Time should be measured with good accuracy
479 return (TMath::Abs(t1 - t2 ) < fTimeGateHigh) ;
483 //____________________________________________________________________________
484 Bool_t AliPHOSClusterizerv1::IsInEmc(AliPHOSDigit * digit) const
486 // Tells if (true) or not (false) the digit is in a PHOS-EMC module
490 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
492 if(digit->GetId() <= nEMC ) rv = kTRUE;
497 //____________________________________________________________________________
498 Bool_t AliPHOSClusterizerv1::IsInCpv(AliPHOSDigit * digit) const
500 // Tells if (true) or not (false) the digit is in a PHOS-CPV module
504 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
506 if(digit->GetId() > nEMC ) rv = kTRUE;
511 //____________________________________________________________________________
512 void AliPHOSClusterizerv1::WriteRecPoints()
515 // Creates new branches with given title
516 // fills and writes into TreeR.
519 //Evaluate position, dispersion and other RecPoint properties..
520 Int_t nEmc = fEMCRecPoints->GetEntriesFast();
521 Float_t emcMinE= AliPHOSReconstructor::GetRecoParam()->GetEMCMinE(); //Minimal digit energy
522 TVector3 fakeVtx(0.,0.,0.) ;
523 for(index = 0; index < nEmc; index++){
524 AliPHOSEmcRecPoint * rp =
525 static_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) );
526 rp->Purify(emcMinE,fDigitsArr) ;
527 if(rp->GetMultiplicity()==0){
528 fEMCRecPoints->RemoveAt(index) ;
533 // No vertex is available now, calculate corrections in PID
534 rp->EvalAll(fDigitsArr) ;
535 rp->EvalCoreEnergy(fW0,fEcoreRadius,fDigitsArr) ;
536 rp->EvalAll(fW0,fakeVtx,fDigitsArr) ;
537 rp->EvalLocal2TrackingCSTransform();
539 fEMCRecPoints->Compress() ;
540 fEMCRecPoints->Sort() ;
541 // fEMCRecPoints->Expand(fEMCRecPoints->GetEntriesFast()) ;
542 for(index = 0; index < fEMCRecPoints->GetEntries(); index++){
543 static_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) )->SetIndexInList(index) ;
546 //For each rec.point set the distance to the nearest bad crystal (BVP)
547 SetDistancesToBadChannels();
549 //Now the same for CPV
550 for(index = 0; index < fCPVRecPoints->GetEntries(); index++){
551 AliPHOSCpvRecPoint * rp = static_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) );
552 rp->EvalAll(fDigitsArr) ;
553 rp->EvalAll(fW0CPV,fakeVtx,fDigitsArr) ;
554 rp->EvalLocal2TrackingCSTransform();
556 fCPVRecPoints->Sort() ;
558 for(index = 0; index < fCPVRecPoints->GetEntries(); index++)
559 static_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) )->SetIndexInList(index) ;
561 fCPVRecPoints->Expand(fCPVRecPoints->GetEntriesFast()) ;
563 if(fWrite){ //We write TreeR
568 //____________________________________________________________________________
569 void AliPHOSClusterizerv1::MakeClusters()
571 // Steering method to construct the clusters stored in a list of Reconstructed Points
572 // A cluster is defined as a list of neighbour digits
574 fNumberOfCpvClusters = 0 ;
575 fNumberOfEmcClusters = 0 ;
577 //Mark all digits as unused yet
578 const Int_t maxNDigits = 3584; // There is no clusters larger than PHOS module ;)
579 Int_t nDigits=fDigitsArr->GetEntriesFast() ;
581 for(Int_t i=0; i<nDigits; i++){
584 Int_t iFirst = 0 ; //first index of digit which potentially can be a part of cluster
585 //e.g. first digit in this module, first CPV digit etc.
586 AliPHOSDigit * digit ;
587 TArrayI clusterdigitslist(maxNDigits) ;
588 AliPHOSRecPoint * clu = 0 ;
589 for(Int_t i=0; i<nDigits; i++){
593 digit=static_cast<AliPHOSDigit*>(fDigitsArr->At(i)) ;
599 //is this digit so energetic that start cluster?
600 AliDebug(2,Form("Digit %d, energy=%f, ID=%d",i,digit->GetEnergy(),digit->GetId()));
601 if (( IsInEmc(digit) && Calibrate(digit->GetEnergy(),digit->GetId()) > fEmcClusteringThreshold ) ||
602 ( IsInCpv(digit) && Calibrate(digit->GetEnergy(),digit->GetId()) > fCpvClusteringThreshold ) ) {
603 Int_t iDigitInCluster = 0 ;
604 if ( IsInEmc(digit) ) {
605 // start a new EMC RecPoint
606 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
607 fEMCRecPoints->Expand(2*fNumberOfEmcClusters+1) ;
609 fEMCRecPoints->AddAt(new AliPHOSEmcRecPoint(""), fNumberOfEmcClusters) ;
610 clu = static_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
611 fNumberOfEmcClusters++ ;
612 clu->AddDigit(*digit, Calibrate(digit->GetEnergy(),digit->GetId()),CalibrateT(digit->GetTime(),digit->GetId(),digit->IsLG())) ;
613 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
615 fDigitsUsed[i]=kTRUE ;
617 // start a new CPV cluster
618 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
619 fCPVRecPoints->Expand(2*fNumberOfCpvClusters+1);
621 fCPVRecPoints->AddAt(new AliPHOSCpvRecPoint(""), fNumberOfCpvClusters) ;
622 clu = static_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
623 fNumberOfCpvClusters++ ;
624 clu->AddDigit(*digit, Calibrate(digit->GetEnergy(),digit->GetId()),0.) ; // no timing information in CPV
625 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
627 fDigitsUsed[i]=kTRUE ;
630 //Now scan remaining digits in list to find neigbours of our seed
632 AliPHOSDigit * digitN ;
634 while (index < iDigitInCluster){ // scan over digits already in cluster
635 digit = static_cast<AliPHOSDigit*>( fDigitsArr->At(clusterdigitslist[index]) ) ;
637 for(Int_t j=iFirst; j<nDigits; j++){
638 if (iDigitInCluster >= maxNDigits) {
639 AliError(Form("The number of digits in cluster is more than %d, skip the rest of event",
644 continue ; //look through remaining digits
645 digitN = static_cast<AliPHOSDigit*>( fDigitsArr->At(j) ) ;
646 Int_t ineb = AreNeighbours(digit, digitN); // call (digit,digitN) in THAT oder !!!!!
648 case -1: //too early (e.g. previous module), do not look before j at subsequent passes
651 case 0 : // not a neighbour
653 case 1 : // are neighbours
654 clu->AddDigit(*digitN, Calibrate(digitN->GetEnergy(),digitN->GetId()),CalibrateT(digitN->GetTime(),digitN->GetId(),digit->IsLG())) ;
655 clusterdigitslist[iDigitInCluster] = j ;
657 fDigitsUsed[j]=kTRUE ;
659 case 2 : // too far from each other
665 endOfLoop: ; //scanned all possible neighbours for this digit
667 } // loop over cluster
673 //____________________________________________________________________________
674 void AliPHOSClusterizerv1::MakeUnfolding()
676 // Unfolds clusters using the shape of an ElectroMagnetic shower
677 // Performs unfolding of all EMC/CPV clusters
679 // Unfold first EMC clusters
680 if(fNumberOfEmcClusters > 0){
682 Int_t nModulesToUnfold = fGeom->GetNModules() ;
684 Int_t numberofNotUnfolded = fNumberOfEmcClusters ;
686 for(index = 0 ; index < numberofNotUnfolded ; index++){
688 AliPHOSEmcRecPoint * emcRecPoint = static_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) ) ;
689 if(emcRecPoint->GetPHOSMod()> nModulesToUnfold)
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,fEmcLocMaxCut,fDigitsArr) ;
697 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
698 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
700 fEMCRecPoints->Remove(emcRecPoint);
701 fEMCRecPoints->Compress() ;
703 fNumberOfEmcClusters -- ;
704 numberofNotUnfolded-- ;
707 emcRecPoint->SetNExMax(1) ; //Only one local maximum
711 delete[] maxAtEnergy ;
714 // Unfolding of EMC clusters finished
717 // Unfold now CPV clusters
718 if(fNumberOfCpvClusters > 0){
720 Int_t nModulesToUnfold = fGeom->GetNModules() ;
722 Int_t numberofCpvNotUnfolded = fNumberOfCpvClusters ;
724 for(index = 0 ; index < numberofCpvNotUnfolded ; index++){
726 AliPHOSRecPoint * recPoint = static_cast<AliPHOSRecPoint *>( fCPVRecPoints->At(index) ) ;
728 if(recPoint->GetPHOSMod()> nModulesToUnfold)
731 AliPHOSEmcRecPoint * emcRecPoint = static_cast<AliPHOSEmcRecPoint*>(recPoint) ;
733 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
734 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
735 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
736 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fCpvLocMaxCut,fDigitsArr) ;
738 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
739 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
740 fCPVRecPoints->Remove(emcRecPoint);
741 fCPVRecPoints->Compress() ;
743 numberofCpvNotUnfolded-- ;
744 fNumberOfCpvClusters-- ;
748 delete[] maxAtEnergy ;
751 //Unfolding of Cpv clusters finished
755 //____________________________________________________________________________
756 Double_t AliPHOSClusterizerv1::ShowerShape(Double_t x, Double_t z)
758 // Shape of the shower (see PHOS TDR)
759 // If you change this function, change also the gradient evaluation in ChiSquare()
761 //for the moment we neglect dependence on the incident angle.
763 Double_t r2 = x*x + z*z ;
764 Double_t r4 = r2*r2 ;
765 Double_t r295 = TMath::Power(r2, 2.95/2.) ;
766 Double_t shape = TMath::Exp( -r4 * (1. / (2.32 + 0.26 * r4) + 0.0316 / (1 + 0.0652 * r295) ) ) ;
770 //____________________________________________________________________________
771 void AliPHOSClusterizerv1::UnfoldCluster(AliPHOSEmcRecPoint * iniEmc,
773 AliPHOSDigit ** maxAt,
774 Float_t * maxAtEnergy)
776 // Performs the unfolding of a cluster with nMax overlapping showers
778 Int_t nPar = 3 * nMax ;
779 Float_t * fitparameters = new Float_t[nPar] ;
781 Bool_t rv = FindFit(iniEmc, maxAt, maxAtEnergy, nPar, fitparameters) ;
784 // Fit failed, return and remove cluster
785 iniEmc->SetNExMax(-1) ;
786 delete[] fitparameters ;
790 // create ufolded rec points and fill them with new energy lists
791 // First calculate energy deposited in each sell in accordance with fit (without fluctuations): efit[]
792 // and later correct this number in acordance with actual energy deposition
794 Int_t nDigits = iniEmc->GetMultiplicity() ;
795 Float_t * efit = new Float_t[nDigits] ;
796 Float_t xDigit=0.,zDigit=0. ;
797 Float_t xpar=0.,zpar=0.,epar=0. ;
799 AliPHOSDigit * digit = 0 ;
800 Int_t * emcDigits = iniEmc->GetDigitsList() ;
806 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
807 digit = static_cast<AliPHOSDigit*>( fDigitsArr->At(emcDigits[iDigit] ) ) ;
808 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
809 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
813 while(iparam < nPar ){
814 xpar = fitparameters[iparam] ;
815 zpar = fitparameters[iparam+1] ;
816 epar = fitparameters[iparam+2] ;
818 // fGeom->GetIncidentVector(fVtx,relid[0],xpar,zpar,vIncid) ;
819 // efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) ;
820 efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
824 // Now create new RecPoints and fill energy lists with efit corrected to fluctuations
825 // so that energy deposited in each cell is distributed betwin new clusters proportionally
826 // to its contribution to efit
828 Float_t * emcEnergies = iniEmc->GetEnergiesList() ;
832 while(iparam < nPar ){
833 xpar = fitparameters[iparam] ;
834 zpar = fitparameters[iparam+1] ;
835 epar = fitparameters[iparam+2] ;
837 // fGeom->GetIncidentVector(fVtx,iniEmc->GetPHOSMod(),xpar,zpar,vIncid) ;
839 AliPHOSEmcRecPoint * emcRP = 0 ;
841 if(iniEmc->IsEmc()){ //create new entries in fEMCRecPoints...
843 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
844 fEMCRecPoints->Expand(2*fNumberOfEmcClusters) ;
846 (*fEMCRecPoints)[fNumberOfEmcClusters] = new AliPHOSEmcRecPoint("") ;
847 emcRP = static_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
848 fNumberOfEmcClusters++ ;
849 emcRP->SetNExMax((Int_t)nPar/3) ;
851 else{//create new entries in fCPVRecPoints
852 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
853 fCPVRecPoints->Expand(2*fNumberOfCpvClusters) ;
855 (*fCPVRecPoints)[fNumberOfCpvClusters] = new AliPHOSCpvRecPoint("") ;
856 emcRP = static_cast<AliPHOSEmcRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
857 fNumberOfCpvClusters++ ;
861 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
862 digit = static_cast<AliPHOSDigit*>( fDigitsArr->At( emcDigits[iDigit] ) ) ;
863 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
864 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
865 // ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) / efit[iDigit] ;
866 ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar) / efit[iDigit] ;
867 eDigit = emcEnergies[iDigit] * ratio ;
868 emcRP->AddDigit( *digit, eDigit,CalibrateT(digit->GetTime(),digit->GetId(),digit->IsLG()) ) ;
872 delete[] fitparameters ;
877 //_____________________________________________________________________________
878 void AliPHOSClusterizerv1::UnfoldingChiSquare(Int_t & nPar, Double_t * Grad, Double_t & fret, Double_t * x, Int_t iflag)
880 // Calculates the Chi square for the cluster unfolding minimization
881 // Number of parameters, Gradient, Chi squared, parameters, what to do
883 TList * toMinuit = static_cast<TList*>( gMinuit->GetObjectFit() ) ;
885 AliPHOSEmcRecPoint * emcRP = static_cast<AliPHOSEmcRecPoint*>( toMinuit->At(0) ) ;
886 TClonesArray * digits = static_cast<TClonesArray*>( toMinuit->At(1) ) ;
887 // A bit buggy way to get an access to the geometry
889 AliPHOSGeometry *geom = static_cast<AliPHOSGeometry *>(toMinuit->At(2));
891 // TVector3 * vtx = static_cast<TVector3*>(toMinuit->At(3)) ; //Vertex position
893 // AliPHOSEmcRecPoint * emcRP = static_cast<AliPHOSEmcRecPoint *>( gMinuit->GetObjectFit() ) ; // EmcRecPoint to fit
895 Int_t * emcDigits = emcRP->GetDigitsList() ;
897 Int_t nOdigits = emcRP->GetDigitsMultiplicity() ;
899 Float_t * emcEnergies = emcRP->GetEnergiesList() ;
906 for(iparam = 0 ; iparam < nPar ; iparam++)
907 Grad[iparam] = 0 ; // Will evaluate gradient
911 AliPHOSDigit * digit ;
914 for( iDigit = 0 ; iDigit < nOdigits ; iDigit++) {
916 digit = static_cast<AliPHOSDigit*>( digits->At( emcDigits[iDigit] ) );
922 geom->AbsToRelNumbering(digit->GetId(), relid) ;
924 geom->RelPosInModule(relid, xDigit, zDigit) ;
926 if(iflag == 2){ // calculate gradient
929 while(iParam < nPar ){
930 Double_t dx = (xDigit - x[iParam]) ;
932 Double_t dz = (zDigit - x[iParam]) ;
934 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),x[iParam-2],x[iParam-1],vInc) ;
935 // efit += x[iParam] * ShowerShape(dx,dz,vInc) ;
936 efit += x[iParam] * ShowerShape(dx,dz) ;
939 Double_t sum = 2. * (efit - emcEnergies[iDigit]) / emcEnergies[iDigit] ; // Here we assume, that sigma = sqrt(E)
941 while(iParam < nPar ){
942 Double_t xpar = x[iParam] ;
943 Double_t zpar = x[iParam+1] ;
944 Double_t epar = x[iParam+2] ;
945 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
946 Double_t dr = TMath::Sqrt( (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) );
947 // Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
948 Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar) ;
949 //DP: No incident angle dependence in gradient yet!!!!!!
950 Double_t r4 = dr*dr*dr*dr ;
951 Double_t r295 = TMath::Power(dr,2.95) ;
952 Double_t deriv =-4. * dr*dr * ( 2.32 / ( (2.32 + 0.26 * r4) * (2.32 + 0.26 * r4) ) +
953 0.0316 * (1. + 0.0171 * r295) / ( ( 1. + 0.0652 * r295) * (1. + 0.0652 * r295) ) ) ;
955 Grad[iParam] += epar * shape * deriv * (xpar - xDigit) ; // Derivative over x
957 Grad[iParam] += epar * shape * deriv * (zpar - zDigit) ; // Derivative over z
959 Grad[iParam] += shape ; // Derivative over energy
966 while(iparam < nPar ){
967 Double_t xpar = x[iparam] ;
968 Double_t zpar = x[iparam+1] ;
969 Double_t epar = x[iparam+2] ;
971 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
972 // efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
973 efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
976 fret += (efit-emcEnergies[iDigit])*(efit-emcEnergies[iDigit])/emcEnergies[iDigit] ;
977 // Here we assume, that sigma = sqrt(E)
982 //____________________________________________________________________________
983 void AliPHOSClusterizerv1::Print(const Option_t *)const
985 // Print clusterizer parameters
988 TString taskName(GetName()) ;
989 taskName.ReplaceAll(Version(), "") ;
991 if( strcmp(GetName(), "") !=0 ) {
993 message = "\n--------------- %s %s -----------\n" ;
994 message += "Clusterizing digits from the file: %s\n" ;
995 message += " Branch: %s\n" ;
996 message += " EMC Clustering threshold = %f\n" ;
997 message += " EMC Local Maximum cut = %f\n" ;
998 message += " EMC Logarothmic weight = %f\n" ;
999 message += " CPV Clustering threshold = %f\n" ;
1000 message += " CPV Local Maximum cut = %f\n" ;
1001 message += " CPV Logarothmic weight = %f\n" ;
1003 message += " Unfolding on\n" ;
1005 message += " Unfolding off\n" ;
1007 message += "------------------------------------------------------------------" ;
1010 message = " AliPHOSClusterizerv1 not initialized " ;
1012 AliInfo(Form("%s, %s %s %s %s %f %f %f %f %f %f", message.Data(),
1017 fEmcClusteringThreshold,
1020 fCpvClusteringThreshold,
1024 //____________________________________________________________________________
1025 void AliPHOSClusterizerv1::PrintRecPoints(Option_t * option)
1027 // Prints list of RecPoints produced at the current pass of AliPHOSClusterizer
1029 AliInfo(Form("\nFound %d EMC RecPoints and %d CPV RecPoints",
1030 fEMCRecPoints->GetEntriesFast(),
1031 fCPVRecPoints->GetEntriesFast() )) ;
1033 if(strstr(option,"all")) {
1034 printf("\n EMC clusters \n") ;
1035 printf("Index Ene(MeV) Multi Module X Y Z Lambdas_1 Lambda_2 # of prim Primaries list\n") ;
1037 for (index = 0 ; index < fEMCRecPoints->GetEntries() ; index++) {
1038 AliPHOSEmcRecPoint * rp = (AliPHOSEmcRecPoint * )fEMCRecPoints->At(index) ;
1040 rp->GetLocalPosition(locpos);
1042 rp->GetElipsAxis(lambda);
1045 primaries = rp->GetPrimaries(nprimaries);
1046 printf("\n%6d %8.2f %3d %2d %4.1f %4.1f %4.1f %4f %4f %2d : ",
1047 rp->GetIndexInList(), rp->GetEnergy(), rp->GetMultiplicity(), rp->GetPHOSMod(),
1048 locpos.X(), locpos.Y(), locpos.Z(), lambda[0], lambda[1], nprimaries) ;
1050 for (Int_t iprimary=0; iprimary<nprimaries; iprimary++) {
1051 printf("%d ", primaries[iprimary] ) ;
1056 //Now plot CPV recPoints
1057 printf("\n CPV clusters \n") ;
1058 printf("Index Ene(MeV) Module X Y Z \n") ;
1059 for (index = 0 ; index < fCPVRecPoints->GetEntries() ; index++) {
1060 AliPHOSCpvRecPoint * rp = (AliPHOSCpvRecPoint * )fCPVRecPoints->At(index) ;
1063 rp->GetLocalPosition(locpos);
1065 printf("\n%6d %8.2f %2d %4.1f %4.1f %4.1f \n",
1066 rp->GetIndexInList(), rp->GetEnergy(), rp->GetPHOSMod(),
1067 locpos.X(), locpos.Y(), locpos.Z()) ;
1073 //____________________________________________________________________________
1074 void AliPHOSClusterizerv1::SetDistancesToBadChannels()
1076 //For each EMC rec. point set the distance to the nearest bad crystal.
1077 //Author: Boris Polichtchouk
1079 if(!fgCalibData->GetNumOfEmcBadChannels()) return;
1082 memset(badIds,0,8000*sizeof(Int_t));
1083 fgCalibData->EmcBadChannelIds(badIds);
1085 AliPHOSEmcRecPoint* rp;
1088 TVector3 gposRecPoint; // global (in ALICE frame) position of rec. point
1089 TVector3 gposBadChannel; // global position of bad crystal
1092 Float_t dist,minDist;
1093 Int_t relid[4]={0,0,0,0} ;
1095 for(Int_t iRP=0; iRP<fEMCRecPoints->GetEntries(); iRP++){
1096 rp = (AliPHOSEmcRecPoint*)fEMCRecPoints->At(iRP);
1097 //evaluate distance to border
1098 relid[0]=rp->GetPHOSMod() ;
1101 Float_t xcorner,zcorner;
1102 fGeom->RelPosInModule(relid,xcorner,zcorner) ; //coordinate of the corner cell
1103 rp->GetLocalPosition(lpos) ;
1104 minDist = 2.2+TMath::Min(-xcorner-TMath::Abs(lpos.X()),-zcorner-TMath::Abs(lpos.Z())); //2.2 - crystal size
1105 for(Int_t iBad=0; iBad<fgCalibData->GetNumOfEmcBadChannels(); iBad++) {
1106 fGeom->AbsToRelNumbering(badIds[iBad],relid) ;
1107 if(relid[0]!=rp->GetPHOSMod()) //We can not evaluate global position directly since
1108 continue ; //bad channels can be in the module which does not exist in simulations.
1109 rp->GetGlobalPosition(gposRecPoint,gmat);
1110 fGeom->RelPosInAlice(badIds[iBad],gposBadChannel);
1111 AliDebug(2,Form("BC position:[%.3f,%.3f,%.3f], RP position:[%.3f,%.3f,%.3f]. E=%.3f\n",
1112 gposBadChannel.X(),gposBadChannel.Y(),gposBadChannel.Z(),
1113 gposRecPoint.X(),gposRecPoint.Y(),gposRecPoint.Z(),rp->GetEnergy()));
1114 dR = gposBadChannel-gposRecPoint;
1116 if(dist<minDist) minDist = dist;
1119 rp->SetDistanceToBadCrystal(minDist);
1123 //==================================================================================
1124 Float_t AliPHOSClusterizerv1::Calibrate(Float_t amp, Int_t absId) const{
1125 // Calibrate EMC digit, i.e. multiply its Amp by a factor read from CDB
1127 const AliPHOSGeometry *geom = AliPHOSGeometry::GetInstance() ;
1129 //Determine rel.position of the cell absolute ID
1131 geom->AbsToRelNumbering(absId,relId);
1132 Int_t module=relId[0];
1133 Int_t row =relId[2];
1134 Int_t column=relId[3];
1136 Float_t calibration = fgCalibData->GetADCchannelCpv(module,column,row);
1137 return amp*calibration ;
1140 Float_t calibration = fgCalibData->GetADCchannelEmc(module,column,row);
1141 return amp*calibration ;
1144 //==================================================================================
1145 Float_t AliPHOSClusterizerv1::CalibrateT(Float_t time, Int_t absId,Bool_t isLG)const{
1146 // Calibrate time in EMC digit
1148 const AliPHOSGeometry *geom = AliPHOSGeometry::GetInstance() ;
1150 //Determine rel.position of the cell absolute ID
1152 geom->AbsToRelNumbering(absId,relId);
1153 Int_t module=relId[0];
1154 Int_t row =relId[2];
1155 Int_t column=relId[3];
1161 time += fgCalibData->GetLGTimeShiftEmc(module,column,row);
1163 time += fgCalibData->GetTimeShiftEmc(module,column,row);