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.113 2007/08/28 12:55:07 policheh
22 * Loaders removed from the reconstruction code (C.Cheshkov)
24 * Revision 1.112 2007/08/22 09:20:50 hristov
25 * Updated QA classes (Yves)
27 * Revision 1.111 2007/08/08 12:11:28 kharlov
28 * Protection against uninitialized fQADM
30 * Revision 1.110 2007/08/07 14:16:00 kharlov
31 * Quality assurance added (Yves Schutz)
33 * Revision 1.109 2007/07/24 17:20:35 policheh
34 * Usage of RecoParam objects instead of hardcoded parameters in reconstruction.
35 * (See $ALICE_ROOT/PHOS/macros/BeamTest2006/RawReconstruction.C).
37 * Revision 1.108 2007/06/18 07:00:51 kharlov
38 * Bug fix for attempt to use AliPHOSEmcRecPoint after its deletion
40 * Revision 1.107 2007/05/25 14:12:26 policheh
41 * Local to tracking CS transformation added for CPV rec. points
43 * Revision 1.106 2007/05/24 13:01:22 policheh
44 * Local to tracking CS transformation invoked for each EMC rec.point
46 * Revision 1.105 2007/05/02 13:41:22 kharlov
47 * Mode protection against absence of calib.data from AliPHOSCalibData to AliPHOSClusterizerv1::GetCalibrationParameters()
49 * Revision 1.104 2007/04/27 16:55:53 kharlov
50 * Calibration stops if PHOS CDB objects do not exist
52 * Revision 1.103 2007/04/11 11:55:45 policheh
53 * SetDistancesToBadChannels() added.
55 * Revision 1.102 2007/03/28 19:18:15 kharlov
56 * RecPoints recalculation in TSM removed
58 * Revision 1.101 2007/03/06 06:51:27 kharlov
59 * Calculation of cluster properties dep. on vertex posponed to TrackSegmentMaker
61 * Revision 1.100 2007/01/10 11:07:26 kharlov
62 * Raw digits writing to file (B.Polichtchouk)
64 * Revision 1.99 2006/11/07 16:49:51 kharlov
65 * Corrections for next event switch in case of raw data (B.Polichtchouk)
67 * Revision 1.98 2006/10/27 17:14:27 kharlov
68 * Introduce AliDebug and AliLog (B.Polichtchouk)
70 * Revision 1.97 2006/08/29 11:41:19 kharlov
71 * Missing implementation of ctors and = operator are added
73 * Revision 1.96 2006/08/25 16:56:30 kharlov
74 * Compliance with Effective C++
76 * Revision 1.95 2006/08/11 12:36:26 cvetan
77 * Update of the PHOS code needed in order to read and reconstruct the beam test raw data (i.e. without an existing galice.root)
79 * Revision 1.94 2006/08/07 12:27:49 hristov
80 * Removing obsolete code which affected the event numbering scheme
82 * Revision 1.93 2006/08/01 12:20:17 cvetan
83 * 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
85 * Revision 1.92 2006/04/29 20:26:46 hristov
86 * Separate EMC and CPV calibration (Yu.Kharlov)
88 * Revision 1.91 2006/04/22 10:30:17 hristov
89 * Add fEnergy to AliPHOSDigit and operate with EMC amplitude in energy units (Yu.Kharlov)
91 * Revision 1.90 2006/04/11 15:22:59 hristov
92 * run number in query set to -1: forces AliCDBManager to use its run number (A.Colla)
94 * Revision 1.89 2006/03/13 14:05:42 kharlov
95 * Calibration objects for EMC and CPV
97 * Revision 1.88 2006/01/11 08:54:52 hristov
98 * Additional protection in case no calibration entry was found
100 * Revision 1.87 2005/11/22 08:46:43 kharlov
101 * Updated to new CDB (Boris Polichtchouk)
103 * Revision 1.86 2005/11/14 21:52:43 hristov
106 * Revision 1.85 2005/09/27 16:08:08 hristov
107 * New version of CDB storage framework (A.Colla)
109 * Revision 1.84 2005/09/21 10:02:47 kharlov
110 * Reading calibration from CDB (Boris Polichtchouk)
112 * Revision 1.82 2005/09/02 15:43:13 kharlov
113 * Add comments in GetCalibrationParameters and Calibrate
115 * Revision 1.81 2005/09/02 14:32:07 kharlov
116 * Calibration of raw data
118 * Revision 1.80 2005/08/24 15:31:36 kharlov
119 * Setting raw digits flag
121 * Revision 1.79 2005/07/25 15:53:53 kharlov
124 * Revision 1.78 2005/05/28 14:19:04 schutz
125 * Compilation warnings fixed by T.P.
129 //*-- Author: Yves Schutz (SUBATECH) & Dmitri Peressounko (SUBATECH & Kurchatov Institute)
130 //////////////////////////////////////////////////////////////////////////////
131 // Clusterization class. Performs clusterization (collects neighbouring active cells) and
132 // unfolds the clusters having several local maxima.
133 // Results are stored in TreeR#, branches PHOSEmcRP (EMC recPoints),
134 // PHOSCpvRP (CPV RecPoints) and AliPHOSClusterizer (Clusterizer with all
135 // parameters including input digits branch title, thresholds etc.)
136 // This TTask is normally called from Reconstructioner, but can as well be used in
139 // root [0] AliPHOSClusterizerv1 * cl = new AliPHOSClusterizerv1(<pointer_to_phos_geometry_onject>)
140 // root [1] cl->Digits2Clusters(digitsTree,clusterTree)
141 // //finds RecPoints in the current event
142 // root [2] cl->SetDigitsBranch("digits2")
143 // //sets another title for Digitis (input) branch
144 // root [3] cl->SetRecPointsBranch("recp2")
145 // //sets another title four output branches
146 // root [4] cl->SetEmcLocalMaxCut(0.03)
147 // //set clusterization parameters
149 // --- ROOT system ---
154 #include "TBenchmark.h"
155 #include "TClonesArray.h"
157 // --- Standard library ---
159 // --- AliRoot header files ---
161 #include "AliConfig.h"
162 #include "AliPHOSGeometry.h"
163 #include "AliPHOSClusterizerv1.h"
164 #include "AliPHOSEmcRecPoint.h"
165 #include "AliPHOSCpvRecPoint.h"
166 #include "AliPHOSDigit.h"
167 #include "AliPHOSDigitizer.h"
168 #include "AliPHOSCalibrationDB.h"
169 #include "AliCDBManager.h"
170 #include "AliCDBStorage.h"
171 #include "AliCDBEntry.h"
172 #include "AliPHOSRecoParam.h"
173 #include "AliPHOSQualAssDataMaker.h"
174 #include "AliPHOSCalibData.h"
175 #include "AliPHOSReconstructor.h"
177 ClassImp(AliPHOSClusterizerv1)
179 //____________________________________________________________________________
180 AliPHOSClusterizerv1::AliPHOSClusterizerv1() :
181 AliPHOSClusterizer(),
182 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
183 fWrite(0), fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
184 fCalibData(0), fADCchanelEmc(0), fADCpedestalEmc(0),
185 fADCchanelCpv(0), fADCpedestalCpv(0), fEmcClusteringThreshold(0),
186 fCpvClusteringThreshold(0), fEmcMinE(0), fCpvMinE(0),
187 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
188 fW0CPV(0), fEmcTimeGate(0),
191 // default ctor (to be used mainly by Streamer)
194 fDefaultInit = kTRUE ;
197 //____________________________________________________________________________
198 AliPHOSClusterizerv1::AliPHOSClusterizerv1(AliPHOSGeometry *geom) :
199 AliPHOSClusterizer(geom),
200 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
201 fWrite(0), fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
202 fCalibData(0), fADCchanelEmc(0), fADCpedestalEmc(0),
203 fADCchanelCpv(0), fADCpedestalCpv(0), fEmcClusteringThreshold(0),
204 fCpvClusteringThreshold(0), fEmcMinE(0), fCpvMinE(0),
205 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
206 fW0CPV(0), fEmcTimeGate(0),
209 // ctor with the indication of the file where header Tree and digits Tree are stored
213 fDefaultInit = kFALSE ;
216 //____________________________________________________________________________
217 AliPHOSClusterizerv1::~AliPHOSClusterizerv1()
223 //____________________________________________________________________________
224 Float_t AliPHOSClusterizerv1::CalibrateEMC(Float_t amp, Int_t absId)
226 // Convert EMC measured amplitude into real energy.
227 // Calibration parameters are taken from calibration data base for raw data,
228 // or from digitizer parameters for simulated data.
232 fGeom->AbsToRelNumbering(absId,relId) ;
233 Int_t module = relId[0];
234 Int_t column = relId[3];
235 Int_t row = relId[2];
236 if(absId <= fEmcCrystals) { // this is EMC
237 fADCchanelEmc = fCalibData->GetADCchannelEmc (module,column,row);
238 return amp*fADCchanelEmc ;
242 if(absId <= fEmcCrystals) // this is EMC
243 return fADCpedestalEmc + amp*fADCchanelEmc ;
248 //____________________________________________________________________________
249 Float_t AliPHOSClusterizerv1::CalibrateCPV(Int_t amp, Int_t absId)
251 // Convert digitized CPV amplitude into charge.
252 // Calibration parameters are taken from calibration data base for raw data,
253 // or from digitizer parameters for simulated data.
257 fGeom->AbsToRelNumbering(absId,relId) ;
258 Int_t module = relId[0];
259 Int_t column = relId[3];
260 Int_t row = relId[2];
261 if(absId > fEmcCrystals) { // this is CPV
262 fADCchanelCpv = fCalibData->GetADCchannelCpv (module,column,row);
263 fADCpedestalCpv = fCalibData->GetADCpedestalCpv(module,column,row);
264 return fADCpedestalCpv + amp*fADCchanelCpv ;
268 if(absId > fEmcCrystals) // this is CPV
269 return fADCpedestalCpv+ amp*fADCchanelCpv ;
274 //____________________________________________________________________________
275 void AliPHOSClusterizerv1::Digits2Clusters(Option_t *option)
277 // Steering method to perform clusterization for one event
278 // The input is the tree with digits.
279 // The output is the tree with clusters.
281 if(strstr(option,"tim"))
282 gBenchmark->Start("PHOSClusterizer");
284 if(strstr(option,"print")) {
289 GetCalibrationParameters() ;
293 AliDebug(2,Form(" ---- Printing clusters (%d)\n",
294 fEMCRecPoints->GetEntries()));
295 if(AliLog::GetGlobalDebugLevel()>1)
296 fEMCRecPoints->Print();
301 //makes the quality assurance data
302 if (GetQualAssDataMaker()) {
303 GetQualAssDataMaker()->SetData(fEMCRecPoints) ;
304 GetQualAssDataMaker()->Exec(AliQualAss::kRECPOINTS) ;
305 GetQualAssDataMaker()->SetData(fCPVRecPoints) ;
306 GetQualAssDataMaker()->Exec(AliQualAss::kRECPOINTS) ;
311 if(strstr(option,"deb"))
312 PrintRecPoints(option) ;
314 // PLEASE FIX BY MOVING IT TO ALIRECONSTRUCTION !!!
315 //Write the quality assurance data only after the last event
316 // if (GetQualAssDataMaker() && fEventCounter == gime->MaxEvent())
317 // GetQualAssDataMaker()->Finish(AliQualAss::kRECPOINTS) ;
319 if(strstr(option,"tim")){
320 gBenchmark->Stop("PHOSClusterizer");
321 AliInfo(Form("took %f seconds for Clusterizing\n",
322 gBenchmark->GetCpuTime("PHOSClusterizer")));
326 //____________________________________________________________________________
327 Bool_t AliPHOSClusterizerv1::FindFit(AliPHOSEmcRecPoint * emcRP, AliPHOSDigit ** maxAt, Float_t * maxAtEnergy,
328 Int_t nPar, Float_t * fitparameters) const
330 // Calls TMinuit to fit the energy distribution of a cluster with several maxima
331 // The initial values for fitting procedure are set equal to the positions of local maxima.
332 // Cluster will be fitted as a superposition of nPar/3 electromagnetic showers
335 gMinuit->mncler(); // Reset Minuit's list of paramters
336 gMinuit->SetPrintLevel(-1) ; // No Printout
337 gMinuit->SetFCN(AliPHOSClusterizerv1::UnfoldingChiSquare) ;
338 // To set the address of the minimization function
340 TList * toMinuit = new TList();
341 toMinuit->AddAt(emcRP,0) ;
342 toMinuit->AddAt(fDigitsArr,1) ;
343 toMinuit->AddAt(fGeom,2) ;
345 gMinuit->SetObjectFit(toMinuit) ; // To tranfer pointer to UnfoldingChiSquare
347 // filling initial values for fit parameters
348 AliPHOSDigit * digit ;
352 Int_t nDigits = (Int_t) nPar / 3 ;
356 for(iDigit = 0; iDigit < nDigits; iDigit++){
357 digit = maxAt[iDigit];
362 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
363 fGeom->RelPosInModule(relid, x, z) ;
365 Float_t energy = maxAtEnergy[iDigit] ;
367 gMinuit->mnparm(index, "x", x, 0.1, 0, 0, ierflg) ;
370 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : x = %f\n", x ) ;
373 gMinuit->mnparm(index, "z", z, 0.1, 0, 0, ierflg) ;
376 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : z =%f\n", z ) ;
379 gMinuit->mnparm(index, "Energy", energy , 0.05*energy, 0., 4.*energy, ierflg) ;
382 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : energy = %f\n", energy ) ;
387 Double_t p0 = 0.1 ; // "Tolerance" Evaluation stops when EDM = 0.0001*p0 ; The number of function call slightly
392 gMinuit->mnexcm("SET STR", &p2, 0, ierflg) ; // force TMinuit to reduce function calls
393 gMinuit->mnexcm("SET GRA", &p1, 1, ierflg) ; // force TMinuit to use my gradient
394 gMinuit->SetMaxIterations(5);
395 gMinuit->mnexcm("SET NOW", &p2 , 0, ierflg) ; // No Warnings
397 gMinuit->mnexcm("MIGRAD", &p0, 0, ierflg) ; // minimize
399 if(ierflg == 4){ // Minimum not found
400 Warning("FindFit", "PHOS Unfolding fit not converged, cluster abandoned\n" );
403 for(index = 0; index < nPar; index++){
406 gMinuit->GetParameter(index, val, err) ; // Returns value and error of parameter index
407 fitparameters[index] = val ;
415 //____________________________________________________________________________
416 void AliPHOSClusterizerv1::GetCalibrationParameters()
418 // Set calibration parameters:
419 // if calibration database exists, they are read from database,
420 // otherwise, reconstruction stops in the constructor of AliPHOSCalibData
422 // It is a user responsilibity to open CDB before reconstruction, for example:
423 // AliCDBStorage* storage = AliCDBManager::Instance()->GetStorage("local://CalibDB");
425 fCalibData = new AliPHOSCalibData(-1); //use AliCDBManager's run number
426 if (fCalibData->GetCalibDataEmc() == 0)
427 AliFatal("Calibration parameters for PHOS EMC not found. Stop reconstruction.\n");
428 if (fCalibData->GetCalibDataCpv() == 0)
429 AliFatal("Calibration parameters for PHOS CPV not found. Stop reconstruction.\n");
433 //____________________________________________________________________________
434 void AliPHOSClusterizerv1::Init()
436 // Make all memory allocations which can not be done in default constructor.
437 // Attach the Clusterizer task to the list of PHOS tasks
439 fEmcCrystals = fGeom->GetNModules() * fGeom->GetNCristalsInModule() ;
442 gMinuit = new TMinuit(100);
446 //____________________________________________________________________________
447 void AliPHOSClusterizerv1::InitParameters()
450 fNumberOfCpvClusters = 0 ;
451 fNumberOfEmcClusters = 0 ;
453 const AliPHOSRecoParam* parEmc = AliPHOSReconstructor::GetRecoParamEmc();
454 if(!parEmc) AliFatal("Reconstruction parameters for EMC not set!");
456 const AliPHOSRecoParam* parCpv = AliPHOSReconstructor::GetRecoParamCpv();
457 if(!parCpv) AliFatal("Reconstruction parameters for CPV not set!");
459 fCpvClusteringThreshold = parCpv->GetClusteringThreshold();
460 fEmcClusteringThreshold = parEmc->GetClusteringThreshold();
462 fEmcLocMaxCut = parEmc->GetLocalMaxCut();
463 fCpvLocMaxCut = parCpv->GetLocalMaxCut();
465 fEmcMinE = parEmc->GetMinE();
466 fCpvMinE = parCpv->GetMinE();
468 fW0 = parEmc->GetLogWeight();
469 fW0CPV = parCpv->GetLogWeight();
471 fEmcTimeGate = 1.e-8 ;
479 fIsOldRCUFormat = kFALSE;
482 //____________________________________________________________________________
483 Int_t AliPHOSClusterizerv1::AreNeighbours(AliPHOSDigit * d1, AliPHOSDigit * d2)const
485 // Gives the neighbourness of two digits = 0 are not neighbour but continue searching
487 // = 2 are not neighbour but do not continue searching
488 // neighbours are defined as digits having at least a common vertex
489 // The order of d1 and d2 is important: first (d1) should be a digit already in a cluster
490 // which is compared to a digit (d2) not yet in a cluster
495 fGeom->AbsToRelNumbering(d1->GetId(), relid1) ;
498 fGeom->AbsToRelNumbering(d2->GetId(), relid2) ;
500 if ( (relid1[0] == relid2[0]) && (relid1[1]==relid2[1]) ) { // inside the same PHOS module
501 Int_t rowdiff = TMath::Abs( relid1[2] - relid2[2] ) ;
502 Int_t coldiff = TMath::Abs( relid1[3] - relid2[3] ) ;
504 if (( coldiff <= 1 ) && ( rowdiff <= 1 )){
505 if((relid1[1] != 0) || (TMath::Abs(d1->GetTime() - d2->GetTime() ) < fEmcTimeGate))
509 if((relid2[2] > relid1[2]) && (relid2[3] > relid1[3]+1))
510 rv = 2; // Difference in row numbers is too large to look further
516 if( (relid1[0] < relid2[0]) || (relid1[1] != relid2[1]) )
523 //____________________________________________________________________________
524 void AliPHOSClusterizerv1::CleanDigits(TClonesArray * digits)
526 // Remove digits with amplitudes below threshold
528 for(Int_t i=0; i<digits->GetEntriesFast(); i++){
529 AliPHOSDigit * digit = static_cast<AliPHOSDigit*>(digits->At(i)) ;
530 if ( (IsInEmc(digit) && CalibrateEMC(digit->GetEnergy(),digit->GetId()) < fEmcMinE) ||
531 (IsInCpv(digit) && CalibrateCPV(digit->GetAmp() ,digit->GetId()) < fCpvMinE) )
532 digits->RemoveAt(i) ;
535 for (Int_t i = 0 ; i < digits->GetEntriesFast() ; i++) {
536 AliPHOSDigit *digit = static_cast<AliPHOSDigit*>( digits->At(i) ) ;
537 digit->SetIndexInList(i) ;
541 //____________________________________________________________________________
542 Bool_t AliPHOSClusterizerv1::IsInEmc(AliPHOSDigit * digit) const
544 // Tells if (true) or not (false) the digit is in a PHOS-EMC module
548 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
550 if(digit->GetId() <= nEMC ) rv = kTRUE;
555 //____________________________________________________________________________
556 Bool_t AliPHOSClusterizerv1::IsInCpv(AliPHOSDigit * digit) const
558 // Tells if (true) or not (false) the digit is in a PHOS-CPV module
562 Int_t nEMC = fGeom->GetNModules()*fGeom->GetNPhi()*fGeom->GetNZ();
564 if(digit->GetId() > nEMC ) rv = kTRUE;
569 //____________________________________________________________________________
570 void AliPHOSClusterizerv1::WriteRecPoints()
573 // Creates new branches with given title
574 // fills and writes into TreeR.
577 //Evaluate position, dispersion and other RecPoint properties..
578 Int_t nEmc = fEMCRecPoints->GetEntriesFast();
579 for(index = 0; index < nEmc; index++){
580 AliPHOSEmcRecPoint * rp =
581 dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) );
582 rp->Purify(fEmcMinE) ;
583 if(rp->GetMultiplicity()==0){
584 fEMCRecPoints->RemoveAt(index) ;
589 // No vertex is available now, calculate corrections in PID
590 rp->EvalAll(fW0,fDigitsArr) ;
591 TVector3 fakeVtx(0.,0.,0.) ;
592 rp->EvalAll(fW0,fakeVtx,fDigitsArr) ;
593 rp->EvalLocal2TrackingCSTransform();
595 fEMCRecPoints->Compress() ;
596 fEMCRecPoints->Sort() ;
597 // fEMCRecPoints->Expand(fEMCRecPoints->GetEntriesFast()) ;
598 for(index = 0; index < fEMCRecPoints->GetEntries(); index++){
599 dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) )->SetIndexInList(index) ;
602 //For each rec.point set the distance to the nearest bad crystal (BVP)
603 SetDistancesToBadChannels();
605 //Now the same for CPV
606 for(index = 0; index < fCPVRecPoints->GetEntries(); index++){
607 AliPHOSCpvRecPoint * rp = dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) );
608 rp->EvalAll(fW0CPV,fDigitsArr) ;
609 rp->EvalLocal2TrackingCSTransform();
611 fCPVRecPoints->Sort() ;
613 for(index = 0; index < fCPVRecPoints->GetEntries(); index++)
614 dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(index) )->SetIndexInList(index) ;
616 fCPVRecPoints->Expand(fCPVRecPoints->GetEntriesFast()) ;
618 if(fWrite){ //We write TreeR
623 //____________________________________________________________________________
624 void AliPHOSClusterizerv1::MakeClusters()
626 // Steering method to construct the clusters stored in a list of Reconstructed Points
627 // A cluster is defined as a list of neighbour digits
629 //Remove digits below threshold
630 CleanDigits(fDigitsArr) ;
632 TClonesArray * digitsC = static_cast<TClonesArray*>( fDigitsArr->Clone() ) ;
634 // Clusterization starts
636 TIter nextdigit(digitsC) ;
637 AliPHOSDigit * digit ;
638 Bool_t notremoved = kTRUE ;
640 while ( (digit = dynamic_cast<AliPHOSDigit *>( nextdigit()) ) ) { // scan over the list of digitsC
643 AliPHOSRecPoint * clu = 0 ;
645 TArrayI clusterdigitslist(1500) ;
648 if (( IsInEmc (digit) &&
649 CalibrateEMC(digit->GetEnergy(),digit->GetId()) > fEmcClusteringThreshold ) ||
651 CalibrateCPV(digit->GetAmp() ,digit->GetId()) > fCpvClusteringThreshold ) ) {
652 Int_t iDigitInCluster = 0 ;
654 if ( IsInEmc(digit) ) {
655 // start a new EMC RecPoint
656 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
657 fEMCRecPoints->Expand(2*fNumberOfEmcClusters+1) ;
659 fEMCRecPoints->AddAt(new AliPHOSEmcRecPoint(""), fNumberOfEmcClusters) ;
660 clu = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
661 fNumberOfEmcClusters++ ;
662 clu->AddDigit(*digit, CalibrateEMC(digit->GetEnergy(),digit->GetId())) ;
663 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
665 digitsC->Remove(digit) ;
669 // start a new CPV cluster
670 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
671 fCPVRecPoints->Expand(2*fNumberOfCpvClusters+1);
673 fCPVRecPoints->AddAt(new AliPHOSCpvRecPoint(""), fNumberOfCpvClusters) ;
675 clu = dynamic_cast<AliPHOSCpvRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
676 fNumberOfCpvClusters++ ;
677 clu->AddDigit(*digit, CalibrateCPV(digit->GetAmp(),digit->GetId()) ) ;
678 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
680 digitsC->Remove(digit) ;
683 // Here we remove remaining EMC digits, which cannot make a cluster
686 while( ( digit = dynamic_cast<AliPHOSDigit *>( nextdigit() ) ) ) {
688 digitsC->Remove(digit) ;
692 notremoved = kFALSE ;
699 AliPHOSDigit * digitN ;
701 while (index < iDigitInCluster){ // scan over digits already in cluster
702 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At(clusterdigitslist[index]) ) ;
704 while ( (digitN = dynamic_cast<AliPHOSDigit *>( nextdigit() ) ) ) { // scan over the reduced list of digits
705 Int_t ineb = AreNeighbours(digit, digitN); // call (digit,digitN) in THAT oder !!!!!
707 case 0 : // not a neighbour
709 case 1 : // are neighbours
710 if (IsInEmc (digitN))
711 clu->AddDigit(*digitN, CalibrateEMC( digitN->GetEnergy(), digitN->GetId() ) );
713 clu->AddDigit(*digitN, CalibrateCPV( digitN->GetAmp() , digitN->GetId() ) );
715 clusterdigitslist[iDigitInCluster] = digitN->GetIndexInList() ;
717 digitsC->Remove(digitN) ;
719 case 2 : // too far from each other
728 } // loop over cluster
739 //____________________________________________________________________________
740 void AliPHOSClusterizerv1::MakeUnfolding()
742 // Unfolds clusters using the shape of an ElectroMagnetic shower
743 // Performs unfolding of all EMC/CPV clusters
745 // Unfold first EMC clusters
746 if(fNumberOfEmcClusters > 0){
748 Int_t nModulesToUnfold = fGeom->GetNModules() ;
750 Int_t numberofNotUnfolded = fNumberOfEmcClusters ;
752 for(index = 0 ; index < numberofNotUnfolded ; index++){
754 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(index) ) ;
755 if(emcRecPoint->GetPHOSMod()> nModulesToUnfold)
758 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
759 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
760 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
761 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fEmcLocMaxCut,fDigitsArr) ;
763 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
764 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
765 fEMCRecPoints->Remove(emcRecPoint);
766 fEMCRecPoints->Compress() ;
768 fNumberOfEmcClusters -- ;
769 numberofNotUnfolded-- ;
772 emcRecPoint->SetNExMax(1) ; //Only one local maximum
776 delete[] maxAtEnergy ;
779 // Unfolding of EMC clusters finished
782 // Unfold now CPV clusters
783 if(fNumberOfCpvClusters > 0){
785 Int_t nModulesToUnfold = fGeom->GetNModules() ;
787 Int_t numberofCpvNotUnfolded = fNumberOfCpvClusters ;
789 for(index = 0 ; index < numberofCpvNotUnfolded ; index++){
791 AliPHOSRecPoint * recPoint = dynamic_cast<AliPHOSRecPoint *>( fCPVRecPoints->At(index) ) ;
793 if(recPoint->GetPHOSMod()> nModulesToUnfold)
796 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint*>(recPoint) ;
798 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
799 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
800 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
801 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fCpvLocMaxCut,fDigitsArr) ;
803 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
804 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
805 fCPVRecPoints->Remove(emcRecPoint);
806 fCPVRecPoints->Compress() ;
808 numberofCpvNotUnfolded-- ;
809 fNumberOfCpvClusters-- ;
813 delete[] maxAtEnergy ;
816 //Unfolding of Cpv clusters finished
820 //____________________________________________________________________________
821 Double_t AliPHOSClusterizerv1::ShowerShape(Double_t x, Double_t z)
823 // Shape of the shower (see PHOS TDR)
824 // If you change this function, change also the gradient evaluation in ChiSquare()
826 //for the moment we neglect dependence on the incident angle.
828 Double_t r2 = x*x + z*z ;
829 Double_t r4 = r2*r2 ;
830 Double_t r295 = TMath::Power(r2, 2.95/2.) ;
831 Double_t shape = TMath::Exp( -r4 * (1. / (2.32 + 0.26 * r4) + 0.0316 / (1 + 0.0652 * r295) ) ) ;
835 //____________________________________________________________________________
836 void AliPHOSClusterizerv1::UnfoldCluster(AliPHOSEmcRecPoint * iniEmc,
838 AliPHOSDigit ** maxAt,
839 Float_t * maxAtEnergy)
841 // Performs the unfolding of a cluster with nMax overlapping showers
843 Int_t nPar = 3 * nMax ;
844 Float_t * fitparameters = new Float_t[nPar] ;
846 Bool_t rv = FindFit(iniEmc, maxAt, maxAtEnergy, nPar, fitparameters) ;
848 // Fit failed, return and remove cluster
849 iniEmc->SetNExMax(-1) ;
850 delete[] fitparameters ;
854 // create ufolded rec points and fill them with new energy lists
855 // First calculate energy deposited in each sell in accordance with fit (without fluctuations): efit[]
856 // and later correct this number in acordance with actual energy deposition
858 Int_t nDigits = iniEmc->GetMultiplicity() ;
859 Float_t * efit = new Float_t[nDigits] ;
860 Float_t xDigit=0.,zDigit=0. ;
861 Float_t xpar=0.,zpar=0.,epar=0. ;
863 AliPHOSDigit * digit = 0 ;
864 Int_t * emcDigits = iniEmc->GetDigitsList() ;
870 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
871 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At(emcDigits[iDigit] ) ) ;
872 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
873 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
877 while(iparam < nPar ){
878 xpar = fitparameters[iparam] ;
879 zpar = fitparameters[iparam+1] ;
880 epar = fitparameters[iparam+2] ;
882 // fGeom->GetIncidentVector(fVtx,relid[0],xpar,zpar,vIncid) ;
883 // efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) ;
884 efit[iDigit] += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
889 // Now create new RecPoints and fill energy lists with efit corrected to fluctuations
890 // so that energy deposited in each cell is distributed betwin new clusters proportionally
891 // to its contribution to efit
893 Float_t * emcEnergies = iniEmc->GetEnergiesList() ;
897 while(iparam < nPar ){
898 xpar = fitparameters[iparam] ;
899 zpar = fitparameters[iparam+1] ;
900 epar = fitparameters[iparam+2] ;
902 // fGeom->GetIncidentVector(fVtx,iniEmc->GetPHOSMod(),xpar,zpar,vIncid) ;
904 AliPHOSEmcRecPoint * emcRP = 0 ;
906 if(iniEmc->IsEmc()){ //create new entries in fEMCRecPoints...
908 if(fNumberOfEmcClusters >= fEMCRecPoints->GetSize())
909 fEMCRecPoints->Expand(2*fNumberOfEmcClusters) ;
911 (*fEMCRecPoints)[fNumberOfEmcClusters] = new AliPHOSEmcRecPoint("") ;
912 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( fEMCRecPoints->At(fNumberOfEmcClusters) ) ;
913 fNumberOfEmcClusters++ ;
914 emcRP->SetNExMax((Int_t)nPar/3) ;
916 else{//create new entries in fCPVRecPoints
917 if(fNumberOfCpvClusters >= fCPVRecPoints->GetSize())
918 fCPVRecPoints->Expand(2*fNumberOfCpvClusters) ;
920 (*fCPVRecPoints)[fNumberOfCpvClusters] = new AliPHOSCpvRecPoint("") ;
921 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( fCPVRecPoints->At(fNumberOfCpvClusters) ) ;
922 fNumberOfCpvClusters++ ;
926 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
927 digit = dynamic_cast<AliPHOSDigit*>( fDigitsArr->At( emcDigits[iDigit] ) ) ;
928 fGeom->AbsToRelNumbering(digit->GetId(), relid) ;
929 fGeom->RelPosInModule(relid, xDigit, zDigit) ;
930 // ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar,vIncid) / efit[iDigit] ;
931 ratio = epar * ShowerShape(xDigit - xpar,zDigit - zpar) / efit[iDigit] ;
932 eDigit = emcEnergies[iDigit] * ratio ;
933 emcRP->AddDigit( *digit, eDigit ) ;
937 delete[] fitparameters ;
942 //_____________________________________________________________________________
943 void AliPHOSClusterizerv1::UnfoldingChiSquare(Int_t & nPar, Double_t * Grad, Double_t & fret, Double_t * x, Int_t iflag)
945 // Calculates the Chi square for the cluster unfolding minimization
946 // Number of parameters, Gradient, Chi squared, parameters, what to do
948 TList * toMinuit = dynamic_cast<TList*>( gMinuit->GetObjectFit() ) ;
950 AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint*>( toMinuit->At(0) ) ;
951 TClonesArray * digits = dynamic_cast<TClonesArray*>( toMinuit->At(1) ) ;
952 // A bit buggy way to get an access to the geometry
954 AliPHOSGeometry *geom = dynamic_cast<AliPHOSGeometry *>(toMinuit->At(2));
956 // TVector3 * vtx = dynamic_cast<TVector3*>(toMinuit->At(3)) ; //Vertex position
958 // AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( gMinuit->GetObjectFit() ) ; // EmcRecPoint to fit
960 Int_t * emcDigits = emcRP->GetDigitsList() ;
962 Int_t nOdigits = emcRP->GetDigitsMultiplicity() ;
964 Float_t * emcEnergies = emcRP->GetEnergiesList() ;
971 for(iparam = 0 ; iparam < nPar ; iparam++)
972 Grad[iparam] = 0 ; // Will evaluate gradient
976 AliPHOSDigit * digit ;
979 for( iDigit = 0 ; iDigit < nOdigits ; iDigit++) {
981 digit = dynamic_cast<AliPHOSDigit*>( digits->At( emcDigits[iDigit] ) );
987 geom->AbsToRelNumbering(digit->GetId(), relid) ;
989 geom->RelPosInModule(relid, xDigit, zDigit) ;
991 if(iflag == 2){ // calculate gradient
994 while(iParam < nPar ){
995 Double_t dx = (xDigit - x[iParam]) ;
997 Double_t dz = (zDigit - x[iParam]) ;
999 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),x[iParam-2],x[iParam-1],vInc) ;
1000 // efit += x[iParam] * ShowerShape(dx,dz,vInc) ;
1001 efit += x[iParam] * ShowerShape(dx,dz) ;
1004 Double_t sum = 2. * (efit - emcEnergies[iDigit]) / emcEnergies[iDigit] ; // Here we assume, that sigma = sqrt(E)
1006 while(iParam < nPar ){
1007 Double_t xpar = x[iParam] ;
1008 Double_t zpar = x[iParam+1] ;
1009 Double_t epar = x[iParam+2] ;
1010 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
1011 Double_t dr = TMath::Sqrt( (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) );
1012 // Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
1013 Double_t shape = sum * ShowerShape(xDigit - xpar,zDigit - zpar) ;
1014 //DP: No incident angle dependence in gradient yet!!!!!!
1015 Double_t r4 = dr*dr*dr*dr ;
1016 Double_t r295 = TMath::Power(dr,2.95) ;
1017 Double_t deriv =-4. * dr*dr * ( 2.32 / ( (2.32 + 0.26 * r4) * (2.32 + 0.26 * r4) ) +
1018 0.0316 * (1. + 0.0171 * r295) / ( ( 1. + 0.0652 * r295) * (1. + 0.0652 * r295) ) ) ;
1020 Grad[iParam] += epar * shape * deriv * (xpar - xDigit) ; // Derivative over x
1022 Grad[iParam] += epar * shape * deriv * (zpar - zDigit) ; // Derivative over z
1024 Grad[iParam] += shape ; // Derivative over energy
1031 while(iparam < nPar ){
1032 Double_t xpar = x[iparam] ;
1033 Double_t zpar = x[iparam+1] ;
1034 Double_t epar = x[iparam+2] ;
1036 // fGeom->GetIncidentVector(*vtx,emcRP->GetPHOSMod(),xpar,zpar,vInc) ;
1037 // efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar,vInc) ;
1038 efit += epar * ShowerShape(xDigit - xpar,zDigit - zpar) ;
1041 fret += (efit-emcEnergies[iDigit])*(efit-emcEnergies[iDigit])/emcEnergies[iDigit] ;
1042 // Here we assume, that sigma = sqrt(E)
1047 //____________________________________________________________________________
1048 void AliPHOSClusterizerv1::Print(const Option_t *)const
1050 // Print clusterizer parameters
1053 TString taskName(GetName()) ;
1054 taskName.ReplaceAll(Version(), "") ;
1056 if( strcmp(GetName(), "") !=0 ) {
1058 message = "\n--------------- %s %s -----------\n" ;
1059 message += "Clusterizing digits from the file: %s\n" ;
1060 message += " Branch: %s\n" ;
1061 message += " EMC Clustering threshold = %f\n" ;
1062 message += " EMC Local Maximum cut = %f\n" ;
1063 message += " EMC Logarothmic weight = %f\n" ;
1064 message += " CPV Clustering threshold = %f\n" ;
1065 message += " CPV Local Maximum cut = %f\n" ;
1066 message += " CPV Logarothmic weight = %f\n" ;
1068 message += " Unfolding on\n" ;
1070 message += " Unfolding off\n" ;
1072 message += "------------------------------------------------------------------" ;
1075 message = " AliPHOSClusterizerv1 not initialized " ;
1077 AliInfo(Form("%s, %s %s %s %s %s %s %s %s %s %s", message.Data(),
1082 fEmcClusteringThreshold,
1085 fCpvClusteringThreshold,
1089 //____________________________________________________________________________
1090 //void AliPHOSClusterizerv1::GetVertex(void)
1091 //{ //Extracts vertex posisition
1099 // if(gAlice && gAlice->GetMCApp() && gAlice->Generator()){
1101 // gAlice->Generator()->GetOrigin(x,y,z) ;
1102 // fVtx.SetXYZ(x,y,z) ;
1107 // fVtx[0]=fVtx[1]=fVtx[2]=0. ;
1110 //____________________________________________________________________________
1111 void AliPHOSClusterizerv1::PrintRecPoints(Option_t * option)
1113 // Prints list of RecPoints produced at the current pass of AliPHOSClusterizer
1115 AliInfo(Form("\nFound %d EMC RecPoints and %d CPV RecPoints",
1116 fEMCRecPoints->GetEntriesFast(),
1117 fCPVRecPoints->GetEntriesFast() )) ;
1119 if(strstr(option,"all")) {
1120 printf("\n EMC clusters \n") ;
1121 printf("Index Ene(MeV) Multi Module X Y Z Lambdas_1 Lambda_2 # of prim Primaries list\n") ;
1123 for (index = 0 ; index < fEMCRecPoints->GetEntries() ; index++) {
1124 AliPHOSEmcRecPoint * rp = (AliPHOSEmcRecPoint * )fEMCRecPoints->At(index) ;
1126 rp->GetLocalPosition(locpos);
1128 rp->GetElipsAxis(lambda);
1131 primaries = rp->GetPrimaries(nprimaries);
1132 printf("\n%6d %8.2f %3d %2d %4.1f %4.1f %4.1f %4f %4f %2d : ",
1133 rp->GetIndexInList(), rp->GetEnergy(), rp->GetMultiplicity(), rp->GetPHOSMod(),
1134 locpos.X(), locpos.Y(), locpos.Z(), lambda[0], lambda[1], nprimaries) ;
1136 for (Int_t iprimary=0; iprimary<nprimaries; iprimary++) {
1137 printf("%d ", primaries[iprimary] ) ;
1142 //Now plot CPV recPoints
1143 printf("\n CPV clusters \n") ;
1144 printf("Index Ene(MeV) Module X Y Z \n") ;
1145 for (index = 0 ; index < fCPVRecPoints->GetEntries() ; index++) {
1146 AliPHOSCpvRecPoint * rp = (AliPHOSCpvRecPoint * )fCPVRecPoints->At(index) ;
1149 rp->GetLocalPosition(locpos);
1151 printf("\n%6d %8.2f %2d %4.1f %4.1f %4.1f \n",
1152 rp->GetIndexInList(), rp->GetEnergy(), rp->GetPHOSMod(),
1153 locpos.X(), locpos.Y(), locpos.Z()) ;
1159 //____________________________________________________________________________
1160 void AliPHOSClusterizerv1::SetDistancesToBadChannels()
1162 //For each EMC rec. point set the distance to the nearest bad crystal.
1163 //Author: Boris Polichtchouk
1165 if(!fCalibData->GetNumOfEmcBadChannels()) return;
1166 AliInfo(Form("%d bad channel(s) found.\n",fCalibData->GetNumOfEmcBadChannels()));
1169 fCalibData->EmcBadChannelIds(badIds);
1171 AliPHOSEmcRecPoint* rp;
1174 TVector3 gposRecPoint; // global (in ALICE frame) position of rec. point
1175 TVector3 gposBadChannel; // global position of bad crystal
1178 Float_t dist,minDist;
1180 for(Int_t iRP=0; iRP<fEMCRecPoints->GetEntries(); iRP++){
1181 rp = (AliPHOSEmcRecPoint*)fEMCRecPoints->At(iRP);
1184 for(Int_t iBad=0; iBad<fCalibData->GetNumOfEmcBadChannels(); iBad++) {
1185 rp->GetGlobalPosition(gposRecPoint,gmat);
1186 fGeom->RelPosInAlice(badIds[iBad],gposBadChannel);
1187 AliDebug(2,Form("BC position:[%.3f,%.3f,%.3f], RP position:[%.3f,%.3f,%.3f]. E=%.3f\n",
1188 gposBadChannel.X(),gposBadChannel.Y(),gposBadChannel.Z(),
1189 gposRecPoint.X(),gposRecPoint.Y(),gposRecPoint.Z(),rp->GetEnergy()));
1190 dR = gposBadChannel-gposRecPoint;
1192 if(dist<minDist) minDist = dist;
1195 rp->SetDistanceToBadCrystal(minDist);