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.97 2006/08/29 11:41:19 kharlov
22 * Missing implementation of ctors and = operator are added
24 * Revision 1.96 2006/08/25 16:56:30 kharlov
25 * Compliance with Effective C++
27 * Revision 1.95 2006/08/11 12:36:26 cvetan
28 * Update of the PHOS code needed in order to read and reconstruct the beam test raw data (i.e. without an existing galice.root)
30 * Revision 1.94 2006/08/07 12:27:49 hristov
31 * Removing obsolete code which affected the event numbering scheme
33 * Revision 1.93 2006/08/01 12:20:17 cvetan
34 * 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
36 * Revision 1.92 2006/04/29 20:26:46 hristov
37 * Separate EMC and CPV calibration (Yu.Kharlov)
39 * Revision 1.91 2006/04/22 10:30:17 hristov
40 * Add fEnergy to AliPHOSDigit and operate with EMC amplitude in energy units (Yu.Kharlov)
42 * Revision 1.90 2006/04/11 15:22:59 hristov
43 * run number in query set to -1: forces AliCDBManager to use its run number (A.Colla)
45 * Revision 1.89 2006/03/13 14:05:42 kharlov
46 * Calibration objects for EMC and CPV
48 * Revision 1.88 2006/01/11 08:54:52 hristov
49 * Additional protection in case no calibration entry was found
51 * Revision 1.87 2005/11/22 08:46:43 kharlov
52 * Updated to new CDB (Boris Polichtchouk)
54 * Revision 1.86 2005/11/14 21:52:43 hristov
57 * Revision 1.85 2005/09/27 16:08:08 hristov
58 * New version of CDB storage framework (A.Colla)
60 * Revision 1.84 2005/09/21 10:02:47 kharlov
61 * Reading calibration from CDB (Boris Polichtchouk)
63 * Revision 1.82 2005/09/02 15:43:13 kharlov
64 * Add comments in GetCalibrationParameters and Calibrate
66 * Revision 1.81 2005/09/02 14:32:07 kharlov
67 * Calibration of raw data
69 * Revision 1.80 2005/08/24 15:31:36 kharlov
70 * Setting raw digits flag
72 * Revision 1.79 2005/07/25 15:53:53 kharlov
75 * Revision 1.78 2005/05/28 14:19:04 schutz
76 * Compilation warnings fixed by T.P.
80 //*-- Author: Yves Schutz (SUBATECH) & Dmitri Peressounko (SUBATECH & Kurchatov Institute)
81 //////////////////////////////////////////////////////////////////////////////
82 // Clusterization class. Performs clusterization (collects neighbouring active cells) and
83 // unfolds the clusters having several local maxima.
84 // Results are stored in TreeR#, branches PHOSEmcRP (EMC recPoints),
85 // PHOSCpvRP (CPV RecPoints) and AliPHOSClusterizer (Clusterizer with all
86 // parameters including input digits branch title, thresholds etc.)
87 // This TTask is normally called from Reconstructioner, but can as well be used in
90 // root [0] AliPHOSClusterizerv1 * cl = new AliPHOSClusterizerv1("galice.root", "recpointsname", "digitsname")
91 // Warning in <TDatabasePDG::TDatabasePDG>: object already instantiated
92 // // reads gAlice from header file "galice.root", uses digits stored in the branch names "digitsname" (default = "Default")
93 // // and saves recpoints in branch named "recpointsname" (default = "digitsname")
94 // root [1] cl->ExecuteTask()
95 // //finds RecPoints in all events stored in galice.root
96 // root [2] cl->SetDigitsBranch("digits2")
97 // //sets another title for Digitis (input) branch
98 // root [3] cl->SetRecPointsBranch("recp2")
99 // //sets another title four output branches
100 // root [4] cl->SetEmcLocalMaxCut(0.03)
101 // //set clusterization parameters
102 // root [5] cl->ExecuteTask("deb all time")
103 // //once more finds RecPoints options are
104 // // deb - print number of found rec points
105 // // deb all - print number of found RecPoints and some their characteristics
106 // // time - print benchmarking results
108 // --- ROOT system ---
113 #include "TBenchmark.h"
115 // --- Standard library ---
117 // --- AliRoot header files ---
119 #include "AliPHOSGetter.h"
120 #include "AliPHOSGeometry.h"
121 #include "AliPHOSClusterizerv1.h"
122 #include "AliPHOSEmcRecPoint.h"
123 #include "AliPHOSCpvRecPoint.h"
124 #include "AliPHOSDigit.h"
125 #include "AliPHOSDigitizer.h"
126 #include "AliPHOSCalibrationDB.h"
127 #include "AliCDBManager.h"
128 #include "AliCDBStorage.h"
129 #include "AliCDBEntry.h"
131 ClassImp(AliPHOSClusterizerv1)
133 //____________________________________________________________________________
134 AliPHOSClusterizerv1::AliPHOSClusterizerv1() :
135 AliPHOSClusterizer(),
136 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
137 fWrite(0), fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
138 fCalibData(0), fADCchanelEmc(0), fADCpedestalEmc(0),
139 fADCchanelCpv(0), fADCpedestalCpv(0), fEmcClusteringThreshold(0),
140 fCpvClusteringThreshold(0), fEmcMinE(0), fCpvMinE(0),
141 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
142 fW0CPV(0), fRecPointsInRun(0), fEmcTimeGate(0),
145 // default ctor (to be used mainly by Streamer)
148 fDefaultInit = kTRUE ;
151 //____________________________________________________________________________
152 AliPHOSClusterizerv1::AliPHOSClusterizerv1(const TString alirunFileName, const TString eventFolderName) :
153 AliPHOSClusterizer(alirunFileName, eventFolderName),
154 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
155 fWrite(0), fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
156 fCalibData(0), fADCchanelEmc(0), fADCpedestalEmc(0),
157 fADCchanelCpv(0), fADCpedestalCpv(0), fEmcClusteringThreshold(0),
158 fCpvClusteringThreshold(0), fEmcMinE(0), fCpvMinE(0),
159 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
160 fW0CPV(0), fRecPointsInRun(0), fEmcTimeGate(0),
163 // ctor with the indication of the file where header Tree and digits Tree are stored
167 fDefaultInit = kFALSE ;
170 //____________________________________________________________________________
171 AliPHOSClusterizerv1::AliPHOSClusterizerv1(const AliPHOSClusterizerv1 & obj) :
172 AliPHOSClusterizer(obj),
173 fDefaultInit(0), fEmcCrystals(0), fToUnfold(0),
174 fWrite(0), fNumberOfEmcClusters(0), fNumberOfCpvClusters(0),
175 fCalibData(0), fADCchanelEmc(0), fADCpedestalEmc(0),
176 fADCchanelCpv(0), fADCpedestalCpv(0), fEmcClusteringThreshold(0),
177 fCpvClusteringThreshold(0), fEmcMinE(0), fCpvMinE(0),
178 fEmcLocMaxCut(0), fW0(0), fCpvLocMaxCut(0),
179 fW0CPV(0), fRecPointsInRun(0), fEmcTimeGate(0),
184 //____________________________________________________________________________
185 AliPHOSClusterizerv1::~AliPHOSClusterizerv1()
190 //____________________________________________________________________________
191 const TString AliPHOSClusterizerv1::BranchName() const
196 //____________________________________________________________________________
197 Float_t AliPHOSClusterizerv1::CalibrateEMC(Float_t amp, Int_t absId)
199 // Convert EMC measured amplitude into real energy.
200 // Calibration parameters are taken from calibration data base for raw data,
201 // or from digitizer parameters for simulated data.
205 AliPHOSGetter *gime = AliPHOSGetter::Instance();
206 gime->PHOSGeometry()->AbsToRelNumbering(absId,relId) ;
207 Int_t module = relId[0];
208 Int_t column = relId[3];
209 Int_t row = relId[2];
210 if(absId <= fEmcCrystals) { // this is EMC
211 fADCchanelEmc = fCalibData->GetADCchannelEmc (module,column,row);
212 return amp*fADCchanelEmc ;
216 if(absId <= fEmcCrystals) // this is EMC
217 return fADCpedestalEmc + amp*fADCchanelEmc ;
222 //____________________________________________________________________________
223 Float_t AliPHOSClusterizerv1::CalibrateCPV(Int_t amp, Int_t absId)
225 // Convert digitized CPV amplitude into charge.
226 // Calibration parameters are taken from calibration data base for raw data,
227 // or from digitizer parameters for simulated data.
231 AliPHOSGetter *gime = AliPHOSGetter::Instance();
232 gime->PHOSGeometry()->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 CPV
237 fADCchanelCpv = fCalibData->GetADCchannelCpv (module,column,row);
238 fADCpedestalCpv = fCalibData->GetADCpedestalCpv(module,column,row);
239 return fADCpedestalCpv + amp*fADCchanelCpv ;
243 if(absId > fEmcCrystals) // this is CPV
244 return fADCpedestalCpv+ amp*fADCchanelCpv ;
249 //____________________________________________________________________________
250 void AliPHOSClusterizerv1::Exec(Option_t *option)
252 // Steering method to perform clusterization for events
253 // in the range from fFirstEvent to fLastEvent.
254 // This range is optionally set by SetEventRange().
255 // if fLastEvent=-1 (by default), then process events until the end.
257 if(strstr(option,"tim"))
258 gBenchmark->Start("PHOSClusterizer");
260 if(strstr(option,"print")) {
265 GetCalibrationParameters() ;
267 AliPHOSGetter * gime = AliPHOSGetter::Instance() ;
269 gime->SetRawDigits(kFALSE);
271 gime->SetRawDigits(kTRUE);
273 if (fLastEvent == -1)
274 fLastEvent = gime->MaxEvent() - 1 ;
276 fLastEvent = TMath::Min(fFirstEvent, gime->MaxEvent()); // one event at the time
277 Int_t nEvents = fLastEvent - fFirstEvent + 1;
280 for (ievent = fFirstEvent; ievent <= fLastEvent; ievent++) {
282 gime->Event(ievent ,"D"); // Read digits from simulated data
284 gime->Event(fRawReader,"W",fIsOldRCUFormat); // Read digits from raw data
286 fNumberOfEmcClusters = fNumberOfCpvClusters = 0 ;
290 AliDebug(2,Form(" ---- Printing clusters (%d) of event %d.\n",
291 gime->EmcRecPoints()->GetEntries(),ievent));
292 if(AliLog::GetGlobalDebugLevel()>1)
293 gime->EmcRecPoints()->Print();
300 if(strstr(option,"deb"))
301 PrintRecPoints(option) ;
303 //increment the total number of recpoints per run
304 fRecPointsInRun += gime->EmcRecPoints()->GetEntriesFast() ;
305 fRecPointsInRun += gime->CpvRecPoints()->GetEntriesFast() ;
308 if(fWrite) //do not unload in "on flight" mode
311 if(strstr(option,"tim")){
312 gBenchmark->Stop("PHOSClusterizer");
313 AliInfo(Form("took %f seconds for Clusterizing %f seconds per event \n",
314 gBenchmark->GetCpuTime("PHOSClusterizer"),
315 gBenchmark->GetCpuTime("PHOSClusterizer")/nEvents )) ;
319 //____________________________________________________________________________
320 Bool_t AliPHOSClusterizerv1::FindFit(AliPHOSEmcRecPoint * emcRP, AliPHOSDigit ** maxAt, Float_t * maxAtEnergy,
321 Int_t nPar, Float_t * fitparameters) const
323 // Calls TMinuit to fit the energy distribution of a cluster with several maxima
324 // The initial values for fitting procedure are set equal to the positions of local maxima.
325 // Cluster will be fitted as a superposition of nPar/3 electromagnetic showers
328 AliPHOSGetter * gime = AliPHOSGetter::Instance();
329 TClonesArray * digits = gime->Digits();
332 gMinuit->mncler(); // Reset Minuit's list of paramters
333 gMinuit->SetPrintLevel(-1) ; // No Printout
334 gMinuit->SetFCN(AliPHOSClusterizerv1::UnfoldingChiSquare) ;
335 // To set the address of the minimization function
337 TList * toMinuit = new TList();
338 toMinuit->AddAt(emcRP,0) ;
339 toMinuit->AddAt(digits,1) ;
341 gMinuit->SetObjectFit(toMinuit) ; // To tranfer pointer to UnfoldingChiSquare
343 // filling initial values for fit parameters
344 AliPHOSDigit * digit ;
348 Int_t nDigits = (Int_t) nPar / 3 ;
352 const AliPHOSGeometry * geom = gime->PHOSGeometry() ;
354 for(iDigit = 0; iDigit < nDigits; iDigit++){
355 digit = maxAt[iDigit];
360 geom->AbsToRelNumbering(digit->GetId(), relid) ;
361 geom->RelPosInModule(relid, x, z) ;
363 Float_t energy = maxAtEnergy[iDigit] ;
365 gMinuit->mnparm(index, "x", x, 0.1, 0, 0, ierflg) ;
368 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : x = %f\n", x ) ;
371 gMinuit->mnparm(index, "z", z, 0.1, 0, 0, ierflg) ;
374 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : z =%f\n", z ) ;
377 gMinuit->mnparm(index, "Energy", energy , 0.05*energy, 0., 4.*energy, ierflg) ;
380 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : energy = %f\n", energy ) ;
385 Double_t p0 = 0.1 ; // "Tolerance" Evaluation stops when EDM = 0.0001*p0 ; The number of function call slightly
390 gMinuit->mnexcm("SET STR", &p2, 0, ierflg) ; // force TMinuit to reduce function calls
391 gMinuit->mnexcm("SET GRA", &p1, 1, ierflg) ; // force TMinuit to use my gradient
392 gMinuit->SetMaxIterations(5);
393 gMinuit->mnexcm("SET NOW", &p2 , 0, ierflg) ; // No Warnings
395 gMinuit->mnexcm("MIGRAD", &p0, 0, ierflg) ; // minimize
397 if(ierflg == 4){ // Minimum not found
398 Warning("FindFit", "PHOS Unfolding fit not converged, cluster abandoned\n" );
401 for(index = 0; index < nPar; index++){
404 gMinuit->GetParameter(index, val, err) ; // Returns value and error of parameter index
405 fitparameters[index] = val ;
413 //____________________________________________________________________________
414 void AliPHOSClusterizerv1::GetCalibrationParameters()
416 // Set calibration parameters:
417 // if calibration database exists, they are read from database,
418 // otherwise, they are taken from digitizer.
420 // It is a user responsilibity to open CDB before reconstruction, for example:
421 // AliCDBStorage* storage = AliCDBManager::Instance()->GetStorage("local://CalibDB");
423 AliPHOSGetter * gime = AliPHOSGetter::Instance();
424 // fCalibData = new AliPHOSCalibData(gAlice->GetRunNumber()); //original
426 fCalibData = new AliPHOSCalibData(-1); //use AliCDBManager's run number
430 if ( !gime->Digitizer() )
431 gime->LoadDigitizer();
432 AliPHOSDigitizer * dig = gime->Digitizer();
433 fADCchanelEmc = dig->GetEMCchannel() ;
434 fADCpedestalEmc = dig->GetEMCpedestal();
436 fADCchanelCpv = dig->GetCPVchannel() ;
437 fADCpedestalCpv = dig->GetCPVpedestal() ;
441 //____________________________________________________________________________
442 void AliPHOSClusterizerv1::Init()
444 // Make all memory allocations which can not be done in default constructor.
445 // Attach the Clusterizer task to the list of PHOS tasks
447 AliPHOSGetter* gime = AliPHOSGetter::Instance() ;
449 gime = AliPHOSGetter::Instance(GetTitle(), fEventFolderName.Data());
451 AliPHOSGeometry * geom = gime->PHOSGeometry();
453 fEmcCrystals = geom->GetNModules() * geom->GetNCristalsInModule() ;
456 gMinuit = new TMinuit(100);
458 if ( !gime->Clusterizer() ) {
459 gime->PostClusterizer(this);
463 //____________________________________________________________________________
464 void AliPHOSClusterizerv1::InitParameters()
467 fNumberOfCpvClusters = 0 ;
468 fNumberOfEmcClusters = 0 ;
470 fCpvClusteringThreshold = 0.0;
471 fEmcClusteringThreshold = 0.2;
473 fEmcLocMaxCut = 0.03 ;
474 fCpvLocMaxCut = 0.03 ;
482 fEmcTimeGate = 1.e-8 ;
486 fRecPointsInRun = 0 ;
492 SetEventRange(0,-1) ;
494 fIsOldRCUFormat = kFALSE;
497 //____________________________________________________________________________
498 Int_t AliPHOSClusterizerv1::AreNeighbours(AliPHOSDigit * d1, AliPHOSDigit * d2)const
500 // Gives the neighbourness of two digits = 0 are not neighbour but continue searching
502 // = 2 are not neighbour but do not continue searching
503 // neighbours are defined as digits having at least a common vertex
504 // The order of d1 and d2 is important: first (d1) should be a digit already in a cluster
505 // which is compared to a digit (d2) not yet in a cluster
507 AliPHOSGeometry * geom = AliPHOSGetter::Instance()->PHOSGeometry() ;
512 geom->AbsToRelNumbering(d1->GetId(), relid1) ;
515 geom->AbsToRelNumbering(d2->GetId(), relid2) ;
517 if ( (relid1[0] == relid2[0]) && (relid1[1]==relid2[1]) ) { // inside the same PHOS module
518 Int_t rowdiff = TMath::Abs( relid1[2] - relid2[2] ) ;
519 Int_t coldiff = TMath::Abs( relid1[3] - relid2[3] ) ;
521 if (( coldiff <= 1 ) && ( rowdiff <= 1 )){
522 if((relid1[1] != 0) || (TMath::Abs(d1->GetTime() - d2->GetTime() ) < fEmcTimeGate))
526 if((relid2[2] > relid1[2]) && (relid2[3] > relid1[3]+1))
527 rv = 2; // Difference in row numbers is too large to look further
533 if( (relid1[0] < relid2[0]) || (relid1[1] != relid2[1]) )
540 //____________________________________________________________________________
541 void AliPHOSClusterizerv1::CleanDigits(TClonesArray * digits)
543 // Remove digits with amplitudes below threshold
545 for(Int_t i=0; i<digits->GetEntriesFast(); i++){
546 AliPHOSDigit * digit = static_cast<AliPHOSDigit*>(digits->At(i)) ;
547 if ( (IsInEmc(digit) && CalibrateEMC(digit->GetEnergy(),digit->GetId()) < fEmcMinE) ||
548 (IsInCpv(digit) && CalibrateCPV(digit->GetAmp() ,digit->GetId()) < fCpvMinE) )
549 digits->RemoveAt(i) ;
552 for (Int_t i = 0 ; i < digits->GetEntriesFast() ; i++) {
553 AliPHOSDigit *digit = static_cast<AliPHOSDigit*>( digits->At(i) ) ;
554 digit->SetIndexInList(i) ;
558 //____________________________________________________________________________
559 Bool_t AliPHOSClusterizerv1::IsInEmc(AliPHOSDigit * digit) const
561 // Tells if (true) or not (false) the digit is in a PHOS-EMC module
564 AliPHOSGeometry * geom = AliPHOSGetter::Instance()->PHOSGeometry() ;
566 Int_t nEMC = geom->GetNModules()*geom->GetNPhi()*geom->GetNZ();
568 if(digit->GetId() <= nEMC ) rv = kTRUE;
573 //____________________________________________________________________________
574 Bool_t AliPHOSClusterizerv1::IsInCpv(AliPHOSDigit * digit) const
576 // Tells if (true) or not (false) the digit is in a PHOS-CPV module
580 AliPHOSGeometry * geom = AliPHOSGetter::Instance()->PHOSGeometry() ;
582 Int_t nEMC = geom->GetNModules()*geom->GetNPhi()*geom->GetNZ();
584 if(digit->GetId() > nEMC ) rv = kTRUE;
589 //____________________________________________________________________________
590 void AliPHOSClusterizerv1::Unload()
592 AliPHOSGetter * gime = AliPHOSGetter::Instance() ;
593 gime->PhosLoader()->UnloadDigits() ;
594 gime->PhosLoader()->UnloadRecPoints() ;
597 //____________________________________________________________________________
598 void AliPHOSClusterizerv1::WriteRecPoints()
601 // Creates new branches with given title
602 // fills and writes into TreeR.
604 AliPHOSGetter * gime = AliPHOSGetter::Instance();
606 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
607 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
608 TClonesArray * digits = gime->Digits() ;
612 //Evaluate position, dispersion and other RecPoint properties..
613 Int_t nEmc = emcRecPoints->GetEntriesFast();
614 for(index = 0; index < nEmc; index++){
615 AliPHOSEmcRecPoint * rp = dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(index) );
616 rp->Purify(fEmcMinE) ;
617 if(rp->GetMultiplicity()>0.) //If this RP is not empty
618 rp->EvalAll(fW0,digits) ;
620 emcRecPoints->RemoveAt(index) ;
624 emcRecPoints->Compress() ;
625 emcRecPoints->Sort() ;
626 // emcRecPoints->Expand(emcRecPoints->GetEntriesFast()) ;
627 for(index = 0; index < emcRecPoints->GetEntries(); index++){
628 dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(index) )->SetIndexInList(index) ;
631 //Now the same for CPV
632 for(index = 0; index < cpvRecPoints->GetEntries(); index++){
633 AliPHOSCpvRecPoint * rp = dynamic_cast<AliPHOSCpvRecPoint *>( cpvRecPoints->At(index) );
634 rp->EvalAll(fW0CPV,digits) ;
636 cpvRecPoints->Sort() ;
638 for(index = 0; index < cpvRecPoints->GetEntries(); index++)
639 dynamic_cast<AliPHOSCpvRecPoint *>( cpvRecPoints->At(index) )->SetIndexInList(index) ;
641 cpvRecPoints->Expand(cpvRecPoints->GetEntriesFast()) ;
643 if(fWrite){ //We write TreeR
644 TTree * treeR = gime->TreeR();
646 Int_t bufferSize = 32000 ;
647 Int_t splitlevel = 0 ;
650 TBranch * emcBranch = treeR->Branch("PHOSEmcRP","TObjArray",&emcRecPoints,bufferSize,splitlevel);
651 emcBranch->SetTitle(BranchName());
654 TBranch * cpvBranch = treeR->Branch("PHOSCpvRP","TObjArray",&cpvRecPoints,bufferSize,splitlevel);
655 cpvBranch->SetTitle(BranchName());
660 gime->WriteRecPoints("OVERWRITE");
661 gime->WriteClusterizer("OVERWRITE");
665 //____________________________________________________________________________
666 void AliPHOSClusterizerv1::MakeClusters()
668 // Steering method to construct the clusters stored in a list of Reconstructed Points
669 // A cluster is defined as a list of neighbour digits
672 AliPHOSGetter * gime = AliPHOSGetter::Instance();
674 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
675 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
677 emcRecPoints->Delete() ;
678 cpvRecPoints->Delete() ;
680 TClonesArray * digits = gime->Digits() ;
682 //Remove digits below threshold
683 CleanDigits(digits) ;
685 TClonesArray * digitsC = static_cast<TClonesArray*>( digits->Clone() ) ;
687 // Clusterization starts
689 TIter nextdigit(digitsC) ;
690 AliPHOSDigit * digit ;
691 Bool_t notremoved = kTRUE ;
693 while ( (digit = dynamic_cast<AliPHOSDigit *>( nextdigit()) ) ) { // scan over the list of digitsC
696 AliPHOSRecPoint * clu = 0 ;
698 TArrayI clusterdigitslist(1500) ;
701 if (( IsInEmc (digit) &&
702 CalibrateEMC(digit->GetEnergy(),digit->GetId()) > fEmcClusteringThreshold ) ||
704 CalibrateCPV(digit->GetAmp() ,digit->GetId()) > fCpvClusteringThreshold ) ) {
705 Int_t iDigitInCluster = 0 ;
707 if ( IsInEmc(digit) ) {
708 // start a new EMC RecPoint
709 if(fNumberOfEmcClusters >= emcRecPoints->GetSize())
710 emcRecPoints->Expand(2*fNumberOfEmcClusters+1) ;
712 emcRecPoints->AddAt(new AliPHOSEmcRecPoint(""), fNumberOfEmcClusters) ;
713 clu = dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(fNumberOfEmcClusters) ) ;
714 fNumberOfEmcClusters++ ;
715 clu->AddDigit(*digit, CalibrateEMC(digit->GetEnergy(),digit->GetId())) ;
716 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
718 digitsC->Remove(digit) ;
722 // start a new CPV cluster
723 if(fNumberOfCpvClusters >= cpvRecPoints->GetSize())
724 cpvRecPoints->Expand(2*fNumberOfCpvClusters+1);
726 cpvRecPoints->AddAt(new AliPHOSCpvRecPoint(""), fNumberOfCpvClusters) ;
728 clu = dynamic_cast<AliPHOSCpvRecPoint *>( cpvRecPoints->At(fNumberOfCpvClusters) ) ;
729 fNumberOfCpvClusters++ ;
730 clu->AddDigit(*digit, CalibrateCPV(digit->GetAmp(),digit->GetId()) ) ;
731 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
733 digitsC->Remove(digit) ;
736 // Here we remove remaining EMC digits, which cannot make a cluster
739 while( ( digit = dynamic_cast<AliPHOSDigit *>( nextdigit() ) ) ) {
741 digitsC->Remove(digit) ;
745 notremoved = kFALSE ;
752 AliPHOSDigit * digitN ;
754 while (index < iDigitInCluster){ // scan over digits already in cluster
755 digit = dynamic_cast<AliPHOSDigit*>( digits->At(clusterdigitslist[index]) ) ;
757 while ( (digitN = dynamic_cast<AliPHOSDigit *>( nextdigit() ) ) ) { // scan over the reduced list of digits
758 Int_t ineb = AreNeighbours(digit, digitN); // call (digit,digitN) in THAT oder !!!!!
760 case 0 : // not a neighbour
762 case 1 : // are neighbours
763 if (IsInEmc (digitN))
764 clu->AddDigit(*digitN, CalibrateEMC( digitN->GetEnergy(), digitN->GetId() ) );
766 clu->AddDigit(*digitN, CalibrateCPV( digitN->GetAmp() , digitN->GetId() ) );
768 clusterdigitslist[iDigitInCluster] = digitN->GetIndexInList() ;
770 digitsC->Remove(digitN) ;
772 case 2 : // too far from each other
781 } // loop over cluster
792 //____________________________________________________________________________
793 void AliPHOSClusterizerv1::MakeUnfolding()
795 // Unfolds clusters using the shape of an ElectroMagnetic shower
796 // Performs unfolding of all EMC/CPV clusters
798 AliPHOSGetter * gime = AliPHOSGetter::Instance();
800 const AliPHOSGeometry * geom = gime->PHOSGeometry() ;
802 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
803 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
804 TClonesArray * digits = gime->Digits() ;
806 // Unfold first EMC clusters
807 if(fNumberOfEmcClusters > 0){
809 Int_t nModulesToUnfold = geom->GetNModules() ;
811 Int_t numberofNotUnfolded = fNumberOfEmcClusters ;
813 for(index = 0 ; index < numberofNotUnfolded ; index++){
815 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(index) ) ;
816 if(emcRecPoint->GetPHOSMod()> nModulesToUnfold)
819 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
820 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
821 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
822 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fEmcLocMaxCut,digits) ;
824 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
825 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
826 emcRecPoints->Remove(emcRecPoint);
827 emcRecPoints->Compress() ;
829 fNumberOfEmcClusters -- ;
830 numberofNotUnfolded-- ;
833 emcRecPoint->SetNExMax(1) ; //Only one local maximum
837 delete[] maxAtEnergy ;
840 // Unfolding of EMC clusters finished
843 // Unfold now CPV clusters
844 if(fNumberOfCpvClusters > 0){
846 Int_t nModulesToUnfold = geom->GetNModules() ;
848 Int_t numberofCpvNotUnfolded = fNumberOfCpvClusters ;
850 for(index = 0 ; index < numberofCpvNotUnfolded ; index++){
852 AliPHOSRecPoint * recPoint = dynamic_cast<AliPHOSRecPoint *>( cpvRecPoints->At(index) ) ;
854 if(recPoint->GetPHOSMod()> nModulesToUnfold)
857 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint*>(recPoint) ;
859 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
860 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
861 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
862 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fCpvLocMaxCut,digits) ;
864 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
865 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
866 cpvRecPoints->Remove(emcRecPoint);
867 cpvRecPoints->Compress() ;
869 numberofCpvNotUnfolded-- ;
870 fNumberOfCpvClusters-- ;
874 delete[] maxAtEnergy ;
877 //Unfolding of Cpv clusters finished
881 //____________________________________________________________________________
882 Double_t AliPHOSClusterizerv1::ShowerShape(Double_t r)
884 // Shape of the shower (see PHOS TDR)
885 // If you change this function, change also the gradient evaluation in ChiSquare()
887 Double_t r4 = r*r*r*r ;
888 Double_t r295 = TMath::Power(r, 2.95) ;
889 Double_t shape = TMath::Exp( -r4 * (1. / (2.32 + 0.26 * r4) + 0.0316 / (1 + 0.0652 * r295) ) ) ;
893 //____________________________________________________________________________
894 void AliPHOSClusterizerv1::UnfoldCluster(AliPHOSEmcRecPoint * iniEmc,
896 AliPHOSDigit ** maxAt,
897 Float_t * maxAtEnergy)
899 // Performs the unfolding of a cluster with nMax overlapping showers
901 AliPHOSGetter * gime = AliPHOSGetter::Instance();
903 const AliPHOSGeometry * geom = gime->PHOSGeometry() ;
905 const TClonesArray * digits = gime->Digits() ;
906 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
907 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
909 Int_t nPar = 3 * nMax ;
910 Float_t * fitparameters = new Float_t[nPar] ;
912 Bool_t rv = FindFit(iniEmc, maxAt, maxAtEnergy, nPar, fitparameters) ;
914 // Fit failed, return and remove cluster
915 iniEmc->SetNExMax(-1) ;
916 delete[] fitparameters ;
920 // create ufolded rec points and fill them with new energy lists
921 // First calculate energy deposited in each sell in accordance with fit (without fluctuations): efit[]
922 // and later correct this number in acordance with actual energy deposition
924 Int_t nDigits = iniEmc->GetMultiplicity() ;
925 Float_t * efit = new Float_t[nDigits] ;
926 Float_t xDigit=0.,zDigit=0.,distance=0. ;
927 Float_t xpar=0.,zpar=0.,epar=0. ;
929 AliPHOSDigit * digit = 0 ;
930 Int_t * emcDigits = iniEmc->GetDigitsList() ;
934 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
935 digit = dynamic_cast<AliPHOSDigit*>( digits->At(emcDigits[iDigit] ) ) ;
936 geom->AbsToRelNumbering(digit->GetId(), relid) ;
937 geom->RelPosInModule(relid, xDigit, zDigit) ;
941 while(iparam < nPar ){
942 xpar = fitparameters[iparam] ;
943 zpar = fitparameters[iparam+1] ;
944 epar = fitparameters[iparam+2] ;
946 distance = (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) ;
947 distance = TMath::Sqrt(distance) ;
948 efit[iDigit] += epar * ShowerShape(distance) ;
953 // Now create new RecPoints and fill energy lists with efit corrected to fluctuations
954 // so that energy deposited in each cell is distributed betwin new clusters proportionally
955 // to its contribution to efit
957 Float_t * emcEnergies = iniEmc->GetEnergiesList() ;
961 while(iparam < nPar ){
962 xpar = fitparameters[iparam] ;
963 zpar = fitparameters[iparam+1] ;
964 epar = fitparameters[iparam+2] ;
967 AliPHOSEmcRecPoint * emcRP = 0 ;
969 if(iniEmc->IsEmc()){ //create new entries in fEmcRecPoints...
971 if(fNumberOfEmcClusters >= emcRecPoints->GetSize())
972 emcRecPoints->Expand(2*fNumberOfEmcClusters) ;
974 (*emcRecPoints)[fNumberOfEmcClusters] = new AliPHOSEmcRecPoint("") ;
975 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(fNumberOfEmcClusters) ) ;
976 fNumberOfEmcClusters++ ;
977 emcRP->SetNExMax((Int_t)nPar/3) ;
979 else{//create new entries in fCpvRecPoints
980 if(fNumberOfCpvClusters >= cpvRecPoints->GetSize())
981 cpvRecPoints->Expand(2*fNumberOfCpvClusters) ;
983 (*cpvRecPoints)[fNumberOfCpvClusters] = new AliPHOSCpvRecPoint("") ;
984 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( cpvRecPoints->At(fNumberOfCpvClusters) ) ;
985 fNumberOfCpvClusters++ ;
989 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
990 digit = dynamic_cast<AliPHOSDigit*>( digits->At( emcDigits[iDigit] ) ) ;
991 geom->AbsToRelNumbering(digit->GetId(), relid) ;
992 geom->RelPosInModule(relid, xDigit, zDigit) ;
993 distance = (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) ;
994 distance = TMath::Sqrt(distance) ;
995 ratio = epar * ShowerShape(distance) / efit[iDigit] ;
996 eDigit = emcEnergies[iDigit] * ratio ;
997 emcRP->AddDigit( *digit, eDigit ) ;
1001 delete[] fitparameters ;
1006 //_____________________________________________________________________________
1007 void AliPHOSClusterizerv1::UnfoldingChiSquare(Int_t & nPar, Double_t * Grad, Double_t & fret, Double_t * x, Int_t iflag)
1009 // Calculates the Chi square for the cluster unfolding minimization
1010 // Number of parameters, Gradient, Chi squared, parameters, what to do
1012 TList * toMinuit = dynamic_cast<TList*>( gMinuit->GetObjectFit() ) ;
1014 AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint*>( toMinuit->At(0) ) ;
1015 TClonesArray * digits = dynamic_cast<TClonesArray*>( toMinuit->At(1) ) ;
1019 // AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( gMinuit->GetObjectFit() ) ; // EmcRecPoint to fit
1021 Int_t * emcDigits = emcRP->GetDigitsList() ;
1023 Int_t nOdigits = emcRP->GetDigitsMultiplicity() ;
1025 Float_t * emcEnergies = emcRP->GetEnergiesList() ;
1027 const AliPHOSGeometry * geom = AliPHOSGetter::Instance()->PHOSGeometry() ;
1032 for(iparam = 0 ; iparam < nPar ; iparam++)
1033 Grad[iparam] = 0 ; // Will evaluate gradient
1037 AliPHOSDigit * digit ;
1040 for( iDigit = 0 ; iDigit < nOdigits ; iDigit++) {
1042 digit = dynamic_cast<AliPHOSDigit*>( digits->At( emcDigits[iDigit] ) );
1048 geom->AbsToRelNumbering(digit->GetId(), relid) ;
1050 geom->RelPosInModule(relid, xDigit, zDigit) ;
1052 if(iflag == 2){ // calculate gradient
1055 while(iParam < nPar ){
1056 Double_t distance = (xDigit - x[iParam]) * (xDigit - x[iParam]) ;
1058 distance += (zDigit - x[iParam]) * (zDigit - x[iParam]) ;
1059 distance = TMath::Sqrt( distance ) ;
1061 efit += x[iParam] * ShowerShape(distance) ;
1064 Double_t sum = 2. * (efit - emcEnergies[iDigit]) / emcEnergies[iDigit] ; // Here we assume, that sigma = sqrt(E)
1066 while(iParam < nPar ){
1067 Double_t xpar = x[iParam] ;
1068 Double_t zpar = x[iParam+1] ;
1069 Double_t epar = x[iParam+2] ;
1070 Double_t dr = TMath::Sqrt( (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) );
1071 Double_t shape = sum * ShowerShape(dr) ;
1072 Double_t r4 = dr*dr*dr*dr ;
1073 Double_t r295 = TMath::Power(dr,2.95) ;
1074 Double_t deriv =-4. * dr*dr * ( 2.32 / ( (2.32 + 0.26 * r4) * (2.32 + 0.26 * r4) ) +
1075 0.0316 * (1. + 0.0171 * r295) / ( ( 1. + 0.0652 * r295) * (1. + 0.0652 * r295) ) ) ;
1077 Grad[iParam] += epar * shape * deriv * (xpar - xDigit) ; // Derivative over x
1079 Grad[iParam] += epar * shape * deriv * (zpar - zDigit) ; // Derivative over z
1081 Grad[iParam] += shape ; // Derivative over energy
1088 while(iparam < nPar ){
1089 Double_t xpar = x[iparam] ;
1090 Double_t zpar = x[iparam+1] ;
1091 Double_t epar = x[iparam+2] ;
1093 Double_t distance = (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) ;
1094 distance = TMath::Sqrt(distance) ;
1095 efit += epar * ShowerShape(distance) ;
1098 fret += (efit-emcEnergies[iDigit])*(efit-emcEnergies[iDigit])/emcEnergies[iDigit] ;
1099 // Here we assume, that sigma = sqrt(E)
1104 //____________________________________________________________________________
1105 void AliPHOSClusterizerv1::Print(const Option_t *)const
1107 // Print clusterizer parameters
1110 TString taskName(GetName()) ;
1111 taskName.ReplaceAll(Version(), "") ;
1113 if( strcmp(GetName(), "") !=0 ) {
1115 message = "\n--------------- %s %s -----------\n" ;
1116 message += "Clusterizing digits from the file: %s\n" ;
1117 message += " Branch: %s\n" ;
1118 message += " EMC Clustering threshold = %f\n" ;
1119 message += " EMC Local Maximum cut = %f\n" ;
1120 message += " EMC Logarothmic weight = %f\n" ;
1121 message += " CPV Clustering threshold = %f\n" ;
1122 message += " CPV Local Maximum cut = %f\n" ;
1123 message += " CPV Logarothmic weight = %f\n" ;
1125 message += " Unfolding on\n" ;
1127 message += " Unfolding off\n" ;
1129 message += "------------------------------------------------------------------" ;
1132 message = " AliPHOSClusterizerv1 not initialized " ;
1134 AliInfo(Form("%s, %s %s %s %s %s %s %s %s %s %s", message.Data(),
1139 fEmcClusteringThreshold,
1142 fCpvClusteringThreshold,
1148 //____________________________________________________________________________
1149 void AliPHOSClusterizerv1::PrintRecPoints(Option_t * option)
1151 // Prints list of RecPoints produced at the current pass of AliPHOSClusterizer
1153 AliPHOSGetter * gime = AliPHOSGetter::Instance();
1155 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
1156 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
1158 AliInfo(Form("\nevent %d \n Found %d EMC RecPoints and %d CPV RecPoints",
1159 gAlice->GetEvNumber(),
1160 emcRecPoints->GetEntriesFast(),
1161 cpvRecPoints->GetEntriesFast() )) ;
1163 fRecPointsInRun += emcRecPoints->GetEntriesFast() ;
1164 fRecPointsInRun += cpvRecPoints->GetEntriesFast() ;
1167 if(strstr(option,"all")) {
1168 printf("\n EMC clusters \n") ;
1169 printf("Index Ene(MeV) Multi Module X Y Z Lambdas_1 Lambda_2 # of prim Primaries list\n") ;
1171 for (index = 0 ; index < emcRecPoints->GetEntries() ; index++) {
1172 AliPHOSEmcRecPoint * rp = (AliPHOSEmcRecPoint * )emcRecPoints->At(index) ;
1174 rp->GetLocalPosition(locpos);
1176 rp->GetElipsAxis(lambda);
1179 primaries = rp->GetPrimaries(nprimaries);
1180 printf("\n%6d %8.2f %3d %2d %4.1f %4.1f %4.1f %4f %4f %2d : ",
1181 rp->GetIndexInList(), rp->GetEnergy(), rp->GetMultiplicity(), rp->GetPHOSMod(),
1182 locpos.X(), locpos.Y(), locpos.Z(), lambda[0], lambda[1], nprimaries) ;
1184 for (Int_t iprimary=0; iprimary<nprimaries; iprimary++) {
1185 printf("%d ", primaries[iprimary] ) ;
1190 //Now plot CPV recPoints
1191 printf("\n CPV clusters \n") ;
1192 printf("Index Ene(MeV) Module X Y Z \n") ;
1193 for (index = 0 ; index < cpvRecPoints->GetEntries() ; index++) {
1194 AliPHOSCpvRecPoint * rp = (AliPHOSCpvRecPoint * )cpvRecPoints->At(index) ;
1197 rp->GetLocalPosition(locpos);
1199 printf("\n%6d %8.2f %2d %4.1f %4.1f %4.1f \n",
1200 rp->GetIndexInList(), rp->GetEnergy(), rp->GetPHOSMod(),
1201 locpos.X(), locpos.Y(), locpos.Z()) ;