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:
21 * Revision 1.115 2007/09/26 14:22:17 cvetan
22 * 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.
24 * Revision 1.114 2007/09/06 16:06:44 kharlov
25 * Absence of sorting results in loose of all unfolded clusters
27 * Revision 1.113 2007/08/28 12:55:07 policheh
28 * Loaders removed from the reconstruction code (C.Cheshkov)
30 * Revision 1.112 2007/08/22 09:20:50 hristov
31 * Updated QA classes (Yves)
33 * Revision 1.111 2007/08/08 12:11:28 kharlov
34 * Protection against uninitialized fQADM
36 * Revision 1.110 2007/08/07 14:16:00 kharlov
37 * Quality assurance added (Yves Schutz)
39 * Revision 1.109 2007/07/24 17:20:35 policheh
40 * Usage of RecoParam objects instead of hardcoded parameters in reconstruction.
41 * (See $ALICE_ROOT/PHOS/macros/BeamTest2006/RawReconstruction.C).
43 * Revision 1.108 2007/06/18 07:00:51 kharlov
44 * Bug fix for attempt to use AliPHOSEmcRecPoint after its deletion
46 * Revision 1.107 2007/05/25 14:12:26 policheh
47 * Local to tracking CS transformation added for CPV rec. points
49 * Revision 1.106 2007/05/24 13:01:22 policheh
50 * Local to tracking CS transformation invoked for each EMC rec.point
52 * Revision 1.105 2007/05/02 13:41:22 kharlov
53 * Mode protection against absence of calib.data from AliPHOSCalibData to AliPHOSClusterizerv1::GetCalibrationParameters()
55 * Revision 1.104 2007/04/27 16:55:53 kharlov
56 * Calibration stops if PHOS CDB objects do not exist
58 * Revision 1.103 2007/04/11 11:55:45 policheh
59 * SetDistancesToBadChannels() added.
61 * Revision 1.102 2007/03/28 19:18:15 kharlov
62 * RecPoints recalculation in TSM removed
64 * Revision 1.101 2007/03/06 06:51:27 kharlov
65 * Calculation of cluster properties dep. on vertex posponed to TrackSegmentMaker
67 * Revision 1.100 2007/01/10 11:07:26 kharlov
68 * Raw digits writing to file (B.Polichtchouk)
70 * Revision 1.99 2006/11/07 16:49:51 kharlov
71 * Corrections for next event switch in case of raw data (B.Polichtchouk)
73 * Revision 1.98 2006/10/27 17:14:27 kharlov
74 * Introduce AliDebug and AliLog (B.Polichtchouk)
76 * Revision 1.97 2006/08/29 11:41:19 kharlov
77 * Missing implementation of ctors and = operator are added
79 * Revision 1.96 2006/08/25 16:56:30 kharlov
80 * Compliance with Effective C++
82 * Revision 1.95 2006/08/11 12:36:26 cvetan
83 * Update of the PHOS code needed in order to read and reconstruct the beam test raw data (i.e. without an existing galice.root)
85 * Revision 1.94 2006/08/07 12:27:49 hristov
86 * Removing obsolete code which affected the event numbering scheme
88 * Revision 1.93 2006/08/01 12:20:17 cvetan
89 * 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
91 * Revision 1.92 2006/04/29 20:26:46 hristov
92 * Separate EMC and CPV calibration (Yu.Kharlov)
94 * Revision 1.91 2006/04/22 10:30:17 hristov
95 * Add fEnergy to AliPHOSDigit and operate with EMC amplitude in energy units (Yu.Kharlov)
97 * Revision 1.90 2006/04/11 15:22:59 hristov
98 * run number in query set to -1: forces AliCDBManager to use its run number (A.Colla)
100 * Revision 1.89 2006/03/13 14:05:42 kharlov
101 * Calibration objects for EMC and CPV
103 * Revision 1.88 2006/01/11 08:54:52 hristov
104 * Additional protection in case no calibration entry was found
106 * Revision 1.87 2005/11/22 08:46:43 kharlov
107 * Updated to new CDB (Boris Polichtchouk)
109 * Revision 1.86 2005/11/14 21:52:43 hristov
112 * Revision 1.85 2005/09/27 16:08:08 hristov
113 * New version of CDB storage framework (A.Colla)
115 * Revision 1.84 2005/09/21 10:02:47 kharlov
116 * Reading calibration from CDB (Boris Polichtchouk)
118 * Revision 1.82 2005/09/02 15:43:13 kharlov
119 * Add comments in GetCalibrationParameters and Calibrate
121 * Revision 1.81 2005/09/02 14:32:07 kharlov
122 * Calibration of raw data
124 * Revision 1.80 2005/08/24 15:31:36 kharlov
125 * Setting raw digits flag
127 * Revision 1.79 2005/07/25 15:53:53 kharlov
130 * Revision 1.78 2005/05/28 14:19:04 schutz
131 * Compilation warnings fixed by T.P.
135 //*-- Author: Yves Schutz (SUBATECH) & Dmitri Peressounko (SUBATECH & Kurchatov Institute)
136 //////////////////////////////////////////////////////////////////////////////
137 // Clusterization class. Performs clusterization (collects neighbouring active cells) and
138 // unfolds the clusters having several local maxima.
139 // Results are stored in TreeR#, branches PHOSEmcRP (EMC recPoints),
140 // PHOSCpvRP (CPV RecPoints) and AliPHOSClusterizer (Clusterizer with all
141 // parameters including input digits branch title, thresholds etc.)
142 // This TTask is normally called from Reconstructioner, but can as well be used in
145 // root [0] AliPHOSClusterizerv1 * cl = new AliPHOSClusterizerv1(<pointer_to_phos_geometry_onject>)
146 // root [1] cl->Digits2Clusters(digitsTree,clusterTree)
147 // //finds RecPoints in the current event
148 // root [2] cl->SetDigitsBranch("digits2")
149 // //sets another title for Digitis (input) branch
150 // root [3] cl->SetRecPointsBranch("recp2")
151 // //sets another title four output branches
152 // root [4] cl->SetEmcLocalMaxCut(0.03)
153 // //set clusterization parameters
155 // --- ROOT system ---
160 #include "TBenchmark.h"
161 #include "TClonesArray.h"
163 // --- Standard library ---
165 // --- AliRoot header files ---
167 #include "AliConfig.h"
168 #include "AliPHOSGeometry.h"
169 #include "AliPHOSClusterizerv1.h"
170 #include "AliPHOSEmcRecPoint.h"
171 #include "AliPHOSCpvRecPoint.h"
172 #include "AliPHOSDigit.h"
173 #include "AliPHOSDigitizer.h"
174 #include "AliPHOSCalibrationDB.h"
175 #include "AliCDBManager.h"
176 #include "AliCDBStorage.h"
177 #include "AliCDBEntry.h"
178 #include "AliPHOSRecoParam.h"
179 #include "AliPHOSCalibData.h"
180 #include "AliPHOSReconstructor.h"
182 ClassImp(AliPHOSClusterizerv1)
184 //____________________________________________________________________________
185 AliPHOSClusterizerv1::AliPHOSClusterizerv1() :
186 AliPHOSClusterizer(),
187 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
188 fWrite(0), fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
189 fADCchanelEmc(0), fADCpedestalEmc(0),
190 fADCchanelCpv(0), fADCpedestalCpv(0), fEmcClusteringThreshold(0),
191 fCpvClusteringThreshold(0), fEmcMinE(0), fCpvMinE(0),
192 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
193 fW0CPV(0), fEmcTimeGate(0),
196 // default ctor (to be used mainly by Streamer)
199 fDefaultInit = kTRUE ;
202 //____________________________________________________________________________
203 AliPHOSClusterizerv1::AliPHOSClusterizerv1(AliPHOSGeometry *geom) :
204 AliPHOSClusterizer(geom),
205 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
206 fWrite(0), fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
207 fADCchanelEmc(0), fADCpedestalEmc(0),
208 fADCchanelCpv(0), fADCpedestalCpv(0), fEmcClusteringThreshold(0),
209 fCpvClusteringThreshold(0), fEmcMinE(0), fCpvMinE(0),
210 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
211 fW0CPV(0), fEmcTimeGate(0),
214 // ctor with the indication of the file where header Tree and digits Tree are stored
218 fDefaultInit = kFALSE ;
221 //____________________________________________________________________________
222 AliPHOSClusterizerv1::~AliPHOSClusterizerv1()
228 //____________________________________________________________________________
229 Float_t AliPHOSClusterizerv1::CalibrateEMC(Float_t amp, Int_t absId)
231 // Convert EMC measured amplitude into real energy.
232 // Calibration parameters are taken from calibration data base for raw data,
233 // or from digitizer parameters for simulated data.
237 fGeom->AbsToRelNumbering(absId,relId) ;
238 Int_t module = relId[0];
239 Int_t column = relId[3];
240 Int_t row = relId[2];
241 if(absId <= fEmcCrystals) { // this is EMC
242 fADCchanelEmc = fgCalibData->GetADCchannelEmc (module,column,row);
243 return amp*fADCchanelEmc ;
247 if(absId <= fEmcCrystals) // this is EMC
248 return fADCpedestalEmc + amp*fADCchanelEmc ;
253 //____________________________________________________________________________
254 Float_t AliPHOSClusterizerv1::CalibrateCPV(Int_t amp, Int_t absId)
256 // Convert digitized CPV amplitude into charge.
257 // Calibration parameters are taken from calibration data base for raw data,
258 // or from digitizer parameters for simulated data.
262 fGeom->AbsToRelNumbering(absId,relId) ;
263 Int_t module = relId[0];
264 Int_t column = relId[3];
265 Int_t row = relId[2];
266 if(absId > fEmcCrystals) { // this is CPV
267 fADCchanelCpv = fgCalibData->GetADCchannelCpv (module,column,row);
268 fADCpedestalCpv = fgCalibData->GetADCpedestalCpv(module,column,row);
269 return fADCpedestalCpv + amp*fADCchanelCpv ;
273 if(absId > fEmcCrystals) // this is CPV
274 return fADCpedestalCpv+ amp*fADCchanelCpv ;
279 //____________________________________________________________________________
280 void AliPHOSClusterizerv1::Digits2Clusters(Option_t *option)
282 // Steering method to perform clusterization for one event
283 // The input is the tree with digits.
284 // The output is the tree with clusters.
286 if(strstr(option,"tim"))
287 gBenchmark->Start("PHOSClusterizer");
289 if(strstr(option,"print")) {
296 AliDebug(2,Form(" ---- Printing clusters (%d)\n",
297 fEMCRecPoints->GetEntries()));
298 if(AliLog::GetGlobalDebugLevel()>1)
299 fEMCRecPoints->Print();
306 if(strstr(option,"deb"))
307 PrintRecPoints(option) ;
309 if(strstr(option,"tim")){
310 gBenchmark->Stop("PHOSClusterizer");
311 AliInfo(Form("took %f seconds for Clusterizing\n",
312 gBenchmark->GetCpuTime("PHOSClusterizer")));
316 //____________________________________________________________________________
317 Bool_t AliPHOSClusterizerv1::FindFit(AliPHOSEmcRecPoint * emcRP, AliPHOSDigit ** maxAt, Float_t * maxAtEnergy,
318 Int_t nPar, Float_t * fitparameters) const
320 // Calls TMinuit to fit the energy distribution of a cluster with several maxima
321 // The initial values for fitting procedure are set equal to the positions of local maxima.
322 // Cluster will be fitted as a superposition of nPar/3 electromagnetic showers
325 gMinuit->mncler(); // Reset Minuit's list of paramters
326 gMinuit->SetPrintLevel(-1) ; // No Printout
327 gMinuit->SetFCN(AliPHOSClusterizerv1::UnfoldingChiSquare) ;
328 // To set the address of the minimization function
330 TList * toMinuit = new TList();
331 toMinuit->AddAt(emcRP,0) ;
332 toMinuit->AddAt(fDigitsArr,1) ;
333 toMinuit->AddAt(fGeom,2) ;
335 gMinuit->SetObjectFit(toMinuit) ; // To tranfer pointer to UnfoldingChiSquare
337 // filling initial values for fit parameters
338 AliPHOSDigit * digit ;
342 Int_t nDigits = (Int_t) nPar / 3 ;
346 for(iDigit = 0; iDigit < nDigits; iDigit++){
347 digit = maxAt[iDigit];
352 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
353 fGeom->RelPosInModule(relid, x, z) ;
355 Float_t energy = maxAtEnergy[iDigit] ;
357 gMinuit->mnparm(index, "x", x, 0.1, 0, 0, ierflg) ;
360 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : x = %f\n", x ) ;
363 gMinuit->mnparm(index, "z", z, 0.1, 0, 0, ierflg) ;
366 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : z =%f\n", z ) ;
369 gMinuit->mnparm(index, "Energy", energy , 0.05*energy, 0., 4.*energy, ierflg) ;
372 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : energy = %f\n", energy ) ;
377 Double_t p0 = 0.1 ; // "Tolerance" Evaluation stops when EDM = 0.0001*p0 ; The number of function call slightly
382 gMinuit->mnexcm("SET STR", &p2, 0, ierflg) ; // force TMinuit to reduce function calls
383 gMinuit->mnexcm("SET GRA", &p1, 1, ierflg) ; // force TMinuit to use my gradient
384 gMinuit->SetMaxIterations(5);
385 gMinuit->mnexcm("SET NOW", &p2 , 0, ierflg) ; // No Warnings
387 gMinuit->mnexcm("MIGRAD", &p0, 0, ierflg) ; // minimize
389 if(ierflg == 4){ // Minimum not found
390 Warning("FindFit", "PHOS Unfolding fit not converged, cluster abandoned\n" );
393 for(index = 0; index < nPar; index++){
396 gMinuit->GetParameter(index, val, err) ; // Returns value and error of parameter index
397 fitparameters[index] = val ;
405 //____________________________________________________________________________
406 void AliPHOSClusterizerv1::GetCalibrationParameters()
408 // Set calibration parameters:
409 // if calibration database exists, they are read from database,
410 // otherwise, reconstruction stops in the constructor of AliPHOSCalibData
412 // It is a user responsilibity to open CDB before reconstruction, for example:
413 // AliCDBStorage* storage = AliCDBManager::Instance()->GetStorage("local://CalibDB");
416 fgCalibData = new AliPHOSCalibData(-1); //use AliCDBManager's run number
417 if (fgCalibData->GetCalibDataEmc() == 0)
418 AliFatal("Calibration parameters for PHOS EMC not found. Stop reconstruction.\n");
419 if (fgCalibData->GetCalibDataCpv() == 0)
420 AliFatal("Calibration parameters for PHOS CPV not found. Stop reconstruction.\n");
424 //____________________________________________________________________________
425 void AliPHOSClusterizerv1::Init()
427 // Make all memory allocations which can not be done in default constructor.
428 // Attach the Clusterizer task to the list of PHOS tasks
430 fEmcCrystals = fGeom->GetNModules() * fGeom->GetNCristalsInModule() ;
433 gMinuit = new TMinuit(100);
435 GetCalibrationParameters() ;
439 //____________________________________________________________________________
440 void AliPHOSClusterizerv1::InitParameters()
443 fNumberOfCpvClusters = 0 ;
444 fNumberOfEmcClusters = 0 ;
446 const AliPHOSRecoParam* parEmc = AliPHOSReconstructor::GetRecoParamEmc();
447 if(!parEmc) AliFatal("Reconstruction parameters for EMC not set!");
449 const AliPHOSRecoParam* parCpv = AliPHOSReconstructor::GetRecoParamCpv();
450 if(!parCpv) AliFatal("Reconstruction parameters for CPV not set!");
452 fCpvClusteringThreshold = parCpv->GetClusteringThreshold();
453 fEmcClusteringThreshold = parEmc->GetClusteringThreshold();
455 fEmcLocMaxCut = parEmc->GetLocalMaxCut();
456 fCpvLocMaxCut = parCpv->GetLocalMaxCut();
458 fEmcMinE = parEmc->GetMinE();
459 fCpvMinE = parCpv->GetMinE();
461 fW0 = parEmc->GetLogWeight();
462 fW0CPV = parCpv->GetLogWeight();
464 fEmcTimeGate = 1.e-8 ;
470 fIsOldRCUFormat = kFALSE;
473 //____________________________________________________________________________
474 Int_t AliPHOSClusterizerv1::AreNeighbours(AliPHOSDigit * d1, AliPHOSDigit * d2)const
476 // Gives the neighbourness of two digits = 0 are not neighbour but continue searching
478 // = 2 are not neighbour but do not continue searching
479 // neighbours are defined as digits having at least a common vertex
480 // The order of d1 and d2 is important: first (d1) should be a digit already in a cluster
481 // which is compared to a digit (d2) not yet in a cluster
486 fGeom->AbsToRelNumbering(d1->GetId(), relid1) ;
489 fGeom->AbsToRelNumbering(d2->GetId(), relid2) ;
491 if ( (relid1[0] == relid2[0]) && (relid1[1]==relid2[1]) ) { // inside the same PHOS module
492 Int_t rowdiff = TMath::Abs( relid1[2] - relid2[2] ) ;
493 Int_t coldiff = TMath::Abs( relid1[3] - relid2[3] ) ;
495 if (( coldiff <= 1 ) && ( rowdiff <= 1 )){
496 if((relid1[1] != 0) || (TMath::Abs(d1->GetTime() - d2->GetTime() ) < fEmcTimeGate))
500 if((relid2[2] > relid1[2]) && (relid2[3] > relid1[3]+1))
501 rv = 2; // Difference in row numbers is too large to look further
507 if( (relid1[0] < relid2[0]) || (relid1[1] != relid2[1]) )
514 //____________________________________________________________________________
515 void AliPHOSClusterizerv1::CleanDigits(TClonesArray * digits)
517 // Remove digits with amplitudes below threshold
519 for(Int_t i=0; i<digits->GetEntriesFast(); i++){
520 AliPHOSDigit * digit = static_cast<AliPHOSDigit*>(digits->At(i)) ;
521 if ( (IsInEmc(digit) && CalibrateEMC(digit->GetEnergy(),digit->GetId()) < fEmcMinE) ||
522 (IsInCpv(digit) && CalibrateCPV(digit->GetAmp() ,digit->GetId()) < fCpvMinE) )
523 digits->RemoveAt(i) ;
526 for (Int_t i = 0 ; i < digits->GetEntriesFast() ; i++) {
527 AliPHOSDigit *digit = static_cast<AliPHOSDigit*>( digits->At(i) ) ;
528 digit->SetIndexInList(i) ;
532 //____________________________________________________________________________
533 Bool_t AliPHOSClusterizerv1::IsInEmc(AliPHOSDigit * digit) const
535 // Tells if (true) or not (false) the digit is in a PHOS-EMC module
539 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
541 if(digit->GetId() <= nEMC ) rv = kTRUE;
546 //____________________________________________________________________________
547 Bool_t AliPHOSClusterizerv1::IsInCpv(AliPHOSDigit * digit) const
549 // Tells if (true) or not (false) the digit is in a PHOS-CPV module
553 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
555 if(digit->GetId() > nEMC ) rv = kTRUE;
560 //____________________________________________________________________________
561 void AliPHOSClusterizerv1::WriteRecPoints()
564 // Creates new branches with given title
565 // fills and writes into TreeR.
568 //Evaluate position, dispersion and other RecPoint properties..
569 Int_t nEmc = fEMCRecPoints->GetEntriesFast();
570 for(index = 0; index < nEmc; index++){
571 AliPHOSEmcRecPoint * rp =
572 dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) );
573 rp->Purify(fEmcMinE) ;
574 if(rp->GetMultiplicity()==0){
575 fEMCRecPoints->RemoveAt(index) ;
580 // No vertex is available now, calculate corrections in PID
581 rp->EvalAll(fW0,fDigitsArr) ;
582 TVector3 fakeVtx(0.,0.,0.) ;
583 rp->EvalAll(fW0,fakeVtx,fDigitsArr) ;
584 rp->EvalLocal2TrackingCSTransform();
586 fEMCRecPoints->Compress() ;
587 fEMCRecPoints->Sort() ;
588 // fEMCRecPoints->Expand(fEMCRecPoints->GetEntriesFast()) ;
589 for(index = 0; index < fEMCRecPoints->GetEntries(); index++){
590 dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) )->SetIndexInList(index) ;
593 //For each rec.point set the distance to the nearest bad crystal (BVP)
594 SetDistancesToBadChannels();
596 //Now the same for CPV
597 for(index = 0; index < fCPVRecPoints->GetEntries(); index++){
598 AliPHOSCpvRecPoint * rp = dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) );
599 rp->EvalAll(fW0CPV,fDigitsArr) ;
600 rp->EvalLocal2TrackingCSTransform();
602 fCPVRecPoints->Sort() ;
604 for(index = 0; index < fCPVRecPoints->GetEntries(); index++)
605 dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) )->SetIndexInList(index) ;
607 fCPVRecPoints->Expand(fCPVRecPoints->GetEntriesFast()) ;
609 if(fWrite){ //We write TreeR
614 //____________________________________________________________________________
615 void AliPHOSClusterizerv1::MakeClusters()
617 // Steering method to construct the clusters stored in a list of Reconstructed Points
618 // A cluster is defined as a list of neighbour digits
620 //Remove digits below threshold
621 CleanDigits(fDigitsArr) ;
623 TClonesArray * digitsC = static_cast<TClonesArray*>( fDigitsArr->Clone() ) ;
625 // Clusterization starts
627 TIter nextdigit(digitsC) ;
628 AliPHOSDigit * digit ;
629 Bool_t notremoved = kTRUE ;
631 while ( (digit = dynamic_cast<AliPHOSDigit *>( nextdigit()) ) ) { // scan over the list of digitsC
634 AliPHOSRecPoint * clu = 0 ;
636 TArrayI clusterdigitslist(1500) ;
639 if (( IsInEmc (digit) &&
640 CalibrateEMC(digit->GetEnergy(),digit->GetId()) > fEmcClusteringThreshold ) ||
642 CalibrateCPV(digit->GetAmp() ,digit->GetId()) > fCpvClusteringThreshold ) ) {
643 Int_t iDigitInCluster = 0 ;
645 if ( IsInEmc(digit) ) {
646 // start a new EMC RecPoint
647 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
648 fEMCRecPoints->Expand(2*fNumberOfEmcClusters+1) ;
650 fEMCRecPoints->AddAt(new AliPHOSEmcRecPoint(""), fNumberOfEmcClusters) ;
651 clu = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
652 fNumberOfEmcClusters++ ;
653 clu->AddDigit(*digit, CalibrateEMC(digit->GetEnergy(),digit->GetId())) ;
654 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
656 digitsC->Remove(digit) ;
660 // start a new CPV cluster
661 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
662 fCPVRecPoints->Expand(2*fNumberOfCpvClusters+1);
664 fCPVRecPoints->AddAt(new AliPHOSCpvRecPoint(""), fNumberOfCpvClusters) ;
666 clu = dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
667 fNumberOfCpvClusters++ ;
668 clu->AddDigit(*digit, CalibrateCPV(digit->GetAmp(),digit->GetId()) ) ;
669 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
671 digitsC->Remove(digit) ;
674 // Here we remove remaining EMC digits, which cannot make a cluster
677 while( ( digit = dynamic_cast<AliPHOSDigit *>( nextdigit() ) ) ) {
679 digitsC->Remove(digit) ;
683 notremoved = kFALSE ;
690 AliPHOSDigit * digitN ;
692 while (index < iDigitInCluster){ // scan over digits already in cluster
693 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At(clusterdigitslist[index]) ) ;
695 while ( (digitN = dynamic_cast<AliPHOSDigit *>( nextdigit() ) ) ) { // scan over the reduced list of digits
696 Int_t ineb = AreNeighbours(digit, digitN); // call (digit,digitN) in THAT oder !!!!!
698 case 0 : // not a neighbour
700 case 1 : // are neighbours
701 if (IsInEmc (digitN))
702 clu->AddDigit(*digitN, CalibrateEMC( digitN->GetEnergy(), digitN->GetId() ) );
704 clu->AddDigit(*digitN, CalibrateCPV( digitN->GetAmp() , digitN->GetId() ) );
706 clusterdigitslist[iDigitInCluster] = digitN->GetIndexInList() ;
708 digitsC->Remove(digitN) ;
710 case 2 : // too far from each other
719 } // loop over cluster
730 //____________________________________________________________________________
731 void AliPHOSClusterizerv1::MakeUnfolding()
733 // Unfolds clusters using the shape of an ElectroMagnetic shower
734 // Performs unfolding of all EMC/CPV clusters
736 // Unfold first EMC clusters
737 if(fNumberOfEmcClusters > 0){
739 Int_t nModulesToUnfold = fGeom->GetNModules() ;
741 Int_t numberofNotUnfolded = fNumberOfEmcClusters ;
743 for(index = 0 ; index < numberofNotUnfolded ; index++){
745 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) ) ;
746 if(emcRecPoint->GetPHOSMod()> nModulesToUnfold)
749 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
750 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
751 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
752 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fEmcLocMaxCut,fDigitsArr) ;
754 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
755 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
756 fEMCRecPoints->Remove(emcRecPoint);
757 fEMCRecPoints->Compress() ;
759 fNumberOfEmcClusters -- ;
760 numberofNotUnfolded-- ;
763 emcRecPoint->SetNExMax(1) ; //Only one local maximum
767 delete[] maxAtEnergy ;
770 // Unfolding of EMC clusters finished
773 // Unfold now CPV clusters
774 if(fNumberOfCpvClusters > 0){
776 Int_t nModulesToUnfold = fGeom->GetNModules() ;
778 Int_t numberofCpvNotUnfolded = fNumberOfCpvClusters ;
780 for(index = 0 ; index < numberofCpvNotUnfolded ; index++){
782 AliPHOSRecPoint * recPoint = dynamic_cast<AliPHOSRecPoint *>( fCPVRecPoints->At(index) ) ;
784 if(recPoint->GetPHOSMod()> nModulesToUnfold)
787 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint*>(recPoint) ;
789 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
790 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
791 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
792 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fCpvLocMaxCut,fDigitsArr) ;
794 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
795 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
796 fCPVRecPoints->Remove(emcRecPoint);
797 fCPVRecPoints->Compress() ;
799 numberofCpvNotUnfolded-- ;
800 fNumberOfCpvClusters-- ;
804 delete[] maxAtEnergy ;
807 //Unfolding of Cpv clusters finished
811 //____________________________________________________________________________
812 Double_t AliPHOSClusterizerv1::ShowerShape(Double_t x, Double_t z)
814 // Shape of the shower (see PHOS TDR)
815 // If you change this function, change also the gradient evaluation in ChiSquare()
817 //for the moment we neglect dependence on the incident angle.
819 Double_t r2 = x*x + z*z ;
820 Double_t r4 = r2*r2 ;
821 Double_t r295 = TMath::Power(r2, 2.95/2.) ;
822 Double_t shape = TMath::Exp( -r4 * (1. / (2.32 + 0.26 * r4) + 0.0316 / (1 + 0.0652 * r295) ) ) ;
826 //____________________________________________________________________________
827 void AliPHOSClusterizerv1::UnfoldCluster(AliPHOSEmcRecPoint * iniEmc,
829 AliPHOSDigit ** maxAt,
830 Float_t * maxAtEnergy)
832 // Performs the unfolding of a cluster with nMax overlapping showers
834 Int_t nPar = 3 * nMax ;
835 Float_t * fitparameters = new Float_t[nPar] ;
837 Bool_t rv = FindFit(iniEmc, maxAt, maxAtEnergy, nPar, fitparameters) ;
839 // Fit failed, return and remove cluster
840 iniEmc->SetNExMax(-1) ;
841 delete[] fitparameters ;
845 // create ufolded rec points and fill them with new energy lists
846 // First calculate energy deposited in each sell in accordance with fit (without fluctuations): efit[]
847 // and later correct this number in acordance with actual energy deposition
849 Int_t nDigits = iniEmc->GetMultiplicity() ;
850 Float_t * efit = new Float_t[nDigits] ;
851 Float_t xDigit=0.,zDigit=0. ;
852 Float_t xpar=0.,zpar=0.,epar=0. ;
854 AliPHOSDigit * digit = 0 ;
855 Int_t * emcDigits = iniEmc->GetDigitsList() ;
861 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
862 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At(emcDigits[iDigit] ) ) ;
863 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
864 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
868 while(iparam < nPar ){
869 xpar = fitparameters[iparam] ;
870 zpar = fitparameters[iparam+1] ;
871 epar = fitparameters[iparam+2] ;
873 // fGeom->GetIncidentVector(fVtx,relid[0],xpar,zpar,vIncid) ;
874 // efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) ;
875 efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
880 // Now create new RecPoints and fill energy lists with efit corrected to fluctuations
881 // so that energy deposited in each cell is distributed betwin new clusters proportionally
882 // to its contribution to efit
884 Float_t * emcEnergies = iniEmc->GetEnergiesList() ;
888 while(iparam < nPar ){
889 xpar = fitparameters[iparam] ;
890 zpar = fitparameters[iparam+1] ;
891 epar = fitparameters[iparam+2] ;
893 // fGeom->GetIncidentVector(fVtx,iniEmc->GetPHOSMod(),xpar,zpar,vIncid) ;
895 AliPHOSEmcRecPoint * emcRP = 0 ;
897 if(iniEmc->IsEmc()){ //create new entries in fEMCRecPoints...
899 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
900 fEMCRecPoints->Expand(2*fNumberOfEmcClusters) ;
902 (*fEMCRecPoints)[fNumberOfEmcClusters] = new AliPHOSEmcRecPoint("") ;
903 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
904 fNumberOfEmcClusters++ ;
905 emcRP->SetNExMax((Int_t)nPar/3) ;
907 else{//create new entries in fCPVRecPoints
908 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
909 fCPVRecPoints->Expand(2*fNumberOfCpvClusters) ;
911 (*fCPVRecPoints)[fNumberOfCpvClusters] = new AliPHOSCpvRecPoint("") ;
912 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
913 fNumberOfCpvClusters++ ;
917 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
918 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At( emcDigits[iDigit] ) ) ;
919 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
920 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
921 // ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) / efit[iDigit] ;
922 ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar) / efit[iDigit] ;
923 eDigit = emcEnergies[iDigit] * ratio ;
924 emcRP->AddDigit( *digit, eDigit ) ;
928 delete[] fitparameters ;
933 //_____________________________________________________________________________
934 void AliPHOSClusterizerv1::UnfoldingChiSquare(Int_t & nPar, Double_t * Grad, Double_t & fret, Double_t * x, Int_t iflag)
936 // Calculates the Chi square for the cluster unfolding minimization
937 // Number of parameters, Gradient, Chi squared, parameters, what to do
939 TList * toMinuit = dynamic_cast<TList*>( gMinuit->GetObjectFit() ) ;
941 AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint*>( toMinuit->At(0) ) ;
942 TClonesArray * digits = dynamic_cast<TClonesArray*>( toMinuit->At(1) ) ;
943 // A bit buggy way to get an access to the geometry
945 AliPHOSGeometry *geom = dynamic_cast<AliPHOSGeometry *>(toMinuit->At(2));
947 // TVector3 * vtx = dynamic_cast<TVector3*>(toMinuit->At(3)) ; //Vertex position
949 // AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( gMinuit->GetObjectFit() ) ; // EmcRecPoint to fit
951 Int_t * emcDigits = emcRP->GetDigitsList() ;
953 Int_t nOdigits = emcRP->GetDigitsMultiplicity() ;
955 Float_t * emcEnergies = emcRP->GetEnergiesList() ;
962 for(iparam = 0 ; iparam < nPar ; iparam++)
963 Grad[iparam] = 0 ; // Will evaluate gradient
967 AliPHOSDigit * digit ;
970 for( iDigit = 0 ; iDigit < nOdigits ; iDigit++) {
972 digit = dynamic_cast<AliPHOSDigit*>( digits->At( emcDigits[iDigit] ) );
978 geom->AbsToRelNumbering(digit->GetId(), relid) ;
980 geom->RelPosInModule(relid, xDigit, zDigit) ;
982 if(iflag == 2){ // calculate gradient
985 while(iParam < nPar ){
986 Double_t dx = (xDigit - x[iParam]) ;
988 Double_t dz = (zDigit - x[iParam]) ;
990 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),x[iParam-2],x[iParam-1],vInc) ;
991 // efit += x[iParam] * ShowerShape(dx,dz,vInc) ;
992 efit += x[iParam] * ShowerShape(dx,dz) ;
995 Double_t sum = 2. * (efit - emcEnergies[iDigit]) / emcEnergies[iDigit] ; // Here we assume, that sigma = sqrt(E)
997 while(iParam < nPar ){
998 Double_t xpar = x[iParam] ;
999 Double_t zpar = x[iParam+1] ;
1000 Double_t epar = x[iParam+2] ;
1001 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
1002 Double_t dr = TMath::Sqrt( (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) );
1003 // Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
1004 Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar) ;
1005 //DP: No incident angle dependence in gradient yet!!!!!!
1006 Double_t r4 = dr*dr*dr*dr ;
1007 Double_t r295 = TMath::Power(dr,2.95) ;
1008 Double_t deriv =-4. * dr*dr * ( 2.32 / ( (2.32 + 0.26 * r4) * (2.32 + 0.26 * r4) ) +
1009 0.0316 * (1. + 0.0171 * r295) / ( ( 1. + 0.0652 * r295) * (1. + 0.0652 * r295) ) ) ;
1011 Grad[iParam] += epar * shape * deriv * (xpar - xDigit) ; // Derivative over x
1013 Grad[iParam] += epar * shape * deriv * (zpar - zDigit) ; // Derivative over z
1015 Grad[iParam] += shape ; // Derivative over energy
1022 while(iparam < nPar ){
1023 Double_t xpar = x[iparam] ;
1024 Double_t zpar = x[iparam+1] ;
1025 Double_t epar = x[iparam+2] ;
1027 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
1028 // efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
1029 efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
1032 fret += (efit-emcEnergies[iDigit])*(efit-emcEnergies[iDigit])/emcEnergies[iDigit] ;
1033 // Here we assume, that sigma = sqrt(E)
1038 //____________________________________________________________________________
1039 void AliPHOSClusterizerv1::Print(const Option_t *)const
1041 // Print clusterizer parameters
1044 TString taskName(GetName()) ;
1045 taskName.ReplaceAll(Version(), "") ;
1047 if( strcmp(GetName(), "") !=0 ) {
1049 message = "\n--------------- %s %s -----------\n" ;
1050 message += "Clusterizing digits from the file: %s\n" ;
1051 message += " Branch: %s\n" ;
1052 message += " EMC Clustering threshold = %f\n" ;
1053 message += " EMC Local Maximum cut = %f\n" ;
1054 message += " EMC Logarothmic weight = %f\n" ;
1055 message += " CPV Clustering threshold = %f\n" ;
1056 message += " CPV Local Maximum cut = %f\n" ;
1057 message += " CPV Logarothmic weight = %f\n" ;
1059 message += " Unfolding on\n" ;
1061 message += " Unfolding off\n" ;
1063 message += "------------------------------------------------------------------" ;
1066 message = " AliPHOSClusterizerv1 not initialized " ;
1068 AliInfo(Form("%s, %s %s %s %s %s %s %s %s %s %s", message.Data(),
1073 fEmcClusteringThreshold,
1076 fCpvClusteringThreshold,
1080 //____________________________________________________________________________
1081 void AliPHOSClusterizerv1::PrintRecPoints(Option_t * option)
1083 // Prints list of RecPoints produced at the current pass of AliPHOSClusterizer
1085 AliInfo(Form("\nFound %d EMC RecPoints and %d CPV RecPoints",
1086 fEMCRecPoints->GetEntriesFast(),
1087 fCPVRecPoints->GetEntriesFast() )) ;
1089 if(strstr(option,"all")) {
1090 printf("\n EMC clusters \n") ;
1091 printf("Index Ene(MeV) Multi Module X Y Z Lambdas_1 Lambda_2 # of prim Primaries list\n") ;
1093 for (index = 0 ; index < fEMCRecPoints->GetEntries() ; index++) {
1094 AliPHOSEmcRecPoint * rp = (AliPHOSEmcRecPoint * )fEMCRecPoints->At(index) ;
1096 rp->GetLocalPosition(locpos);
1098 rp->GetElipsAxis(lambda);
1101 primaries = rp->GetPrimaries(nprimaries);
1102 printf("\n%6d %8.2f %3d %2d %4.1f %4.1f %4.1f %4f %4f %2d : ",
1103 rp->GetIndexInList(), rp->GetEnergy(), rp->GetMultiplicity(), rp->GetPHOSMod(),
1104 locpos.X(), locpos.Y(), locpos.Z(), lambda[0], lambda[1], nprimaries) ;
1106 for (Int_t iprimary=0; iprimary<nprimaries; iprimary++) {
1107 printf("%d ", primaries[iprimary] ) ;
1112 //Now plot CPV recPoints
1113 printf("\n CPV clusters \n") ;
1114 printf("Index Ene(MeV) Module X Y Z \n") ;
1115 for (index = 0 ; index < fCPVRecPoints->GetEntries() ; index++) {
1116 AliPHOSCpvRecPoint * rp = (AliPHOSCpvRecPoint * )fCPVRecPoints->At(index) ;
1119 rp->GetLocalPosition(locpos);
1121 printf("\n%6d %8.2f %2d %4.1f %4.1f %4.1f \n",
1122 rp->GetIndexInList(), rp->GetEnergy(), rp->GetPHOSMod(),
1123 locpos.X(), locpos.Y(), locpos.Z()) ;
1129 //____________________________________________________________________________
1130 void AliPHOSClusterizerv1::SetDistancesToBadChannels()
1132 //For each EMC rec. point set the distance to the nearest bad crystal.
1133 //Author: Boris Polichtchouk
1135 if(!fgCalibData->GetNumOfEmcBadChannels()) return;
1136 AliInfo(Form("%d bad channel(s) found.\n",fgCalibData->GetNumOfEmcBadChannels()));
1139 fgCalibData->EmcBadChannelIds(badIds);
1141 AliPHOSEmcRecPoint* rp;
1144 TVector3 gposRecPoint; // global (in ALICE frame) position of rec. point
1145 TVector3 gposBadChannel; // global position of bad crystal
1148 Float_t dist,minDist;
1150 for(Int_t iRP=0; iRP<fEMCRecPoints->GetEntries(); iRP++){
1151 rp = (AliPHOSEmcRecPoint*)fEMCRecPoints->At(iRP);
1154 for(Int_t iBad=0; iBad<fgCalibData->GetNumOfEmcBadChannels(); iBad++) {
1155 rp->GetGlobalPosition(gposRecPoint,gmat);
1156 fGeom->RelPosInAlice(badIds[iBad],gposBadChannel);
1157 AliDebug(2,Form("BC position:[%.3f,%.3f,%.3f], RP position:[%.3f,%.3f,%.3f]. E=%.3f\n",
1158 gposBadChannel.X(),gposBadChannel.Y(),gposBadChannel.Z(),
1159 gposRecPoint.X(),gposRecPoint.Y(),gposRecPoint.Z(),rp->GetEnergy()));
1160 dR = gposBadChannel-gposRecPoint;
1162 if(dist<minDist) minDist = dist;
1165 rp->SetDistanceToBadCrystal(minDist);