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.94 2006/08/07 12:27:49 hristov
22 * Removing obsolete code which affected the event numbering scheme
24 * Revision 1.93 2006/08/01 12:20:17 cvetan
25 * 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
27 * Revision 1.92 2006/04/29 20:26:46 hristov
28 * Separate EMC and CPV calibration (Yu.Kharlov)
30 * Revision 1.91 2006/04/22 10:30:17 hristov
31 * Add fEnergy to AliPHOSDigit and operate with EMC amplitude in energy units (Yu.Kharlov)
33 * Revision 1.90 2006/04/11 15:22:59 hristov
34 * run number in query set to -1: forces AliCDBManager to use its run number (A.Colla)
36 * Revision 1.89 2006/03/13 14:05:42 kharlov
37 * Calibration objects for EMC and CPV
39 * Revision 1.88 2006/01/11 08:54:52 hristov
40 * Additional protection in case no calibration entry was found
42 * Revision 1.87 2005/11/22 08:46:43 kharlov
43 * Updated to new CDB (Boris Polichtchouk)
45 * Revision 1.86 2005/11/14 21:52:43 hristov
48 * Revision 1.85 2005/09/27 16:08:08 hristov
49 * New version of CDB storage framework (A.Colla)
51 * Revision 1.84 2005/09/21 10:02:47 kharlov
52 * Reading calibration from CDB (Boris Polichtchouk)
54 * Revision 1.82 2005/09/02 15:43:13 kharlov
55 * Add comments in GetCalibrationParameters and Calibrate
57 * Revision 1.81 2005/09/02 14:32:07 kharlov
58 * Calibration of raw data
60 * Revision 1.80 2005/08/24 15:31:36 kharlov
61 * Setting raw digits flag
63 * Revision 1.79 2005/07/25 15:53:53 kharlov
66 * Revision 1.78 2005/05/28 14:19:04 schutz
67 * Compilation warnings fixed by T.P.
71 //*-- Author: Yves Schutz (SUBATECH) & Dmitri Peressounko (SUBATECH & Kurchatov Institute)
72 //////////////////////////////////////////////////////////////////////////////
73 // Clusterization class. Performs clusterization (collects neighbouring active cells) and
74 // unfolds the clusters having several local maxima.
75 // Results are stored in TreeR#, branches PHOSEmcRP (EMC recPoints),
76 // PHOSCpvRP (CPV RecPoints) and AliPHOSClusterizer (Clusterizer with all
77 // parameters including input digits branch title, thresholds etc.)
78 // This TTask is normally called from Reconstructioner, but can as well be used in
81 // root [0] AliPHOSClusterizerv1 * cl = new AliPHOSClusterizerv1("galice.root", "recpointsname", "digitsname")
82 // Warning in <TDatabasePDG::TDatabasePDG>: object already instantiated
83 // // reads gAlice from header file "galice.root", uses digits stored in the branch names "digitsname" (default = "Default")
84 // // and saves recpoints in branch named "recpointsname" (default = "digitsname")
85 // root [1] cl->ExecuteTask()
86 // //finds RecPoints in all events stored in galice.root
87 // root [2] cl->SetDigitsBranch("digits2")
88 // //sets another title for Digitis (input) branch
89 // root [3] cl->SetRecPointsBranch("recp2")
90 // //sets another title four output branches
91 // root [4] cl->SetEmcLocalMaxCut(0.03)
92 // //set clusterization parameters
93 // root [5] cl->ExecuteTask("deb all time")
94 // //once more finds RecPoints options are
95 // // deb - print number of found rec points
96 // // deb all - print number of found RecPoints and some their characteristics
97 // // time - print benchmarking results
99 // --- ROOT system ---
104 #include "TBenchmark.h"
106 // --- Standard library ---
108 // --- AliRoot header files ---
110 #include "AliPHOSGetter.h"
111 #include "AliPHOSGeometry.h"
112 #include "AliPHOSClusterizerv1.h"
113 #include "AliPHOSEmcRecPoint.h"
114 #include "AliPHOSCpvRecPoint.h"
115 #include "AliPHOSDigit.h"
116 #include "AliPHOSDigitizer.h"
117 #include "AliPHOSCalibrationDB.h"
118 #include "AliCDBManager.h"
119 #include "AliCDBStorage.h"
120 #include "AliCDBEntry.h"
122 ClassImp(AliPHOSClusterizerv1)
124 //____________________________________________________________________________
125 AliPHOSClusterizerv1::AliPHOSClusterizerv1() : AliPHOSClusterizer()
127 // default ctor (to be used mainly by Streamer)
130 fDefaultInit = kTRUE ;
133 //____________________________________________________________________________
134 AliPHOSClusterizerv1::AliPHOSClusterizerv1(const TString alirunFileName, const TString eventFolderName)
135 :AliPHOSClusterizer(alirunFileName, eventFolderName)
137 // ctor with the indication of the file where header Tree and digits Tree are stored
141 fDefaultInit = kFALSE ;
144 //____________________________________________________________________________
145 AliPHOSClusterizerv1::~AliPHOSClusterizerv1()
150 //____________________________________________________________________________
151 const TString AliPHOSClusterizerv1::BranchName() const
156 //____________________________________________________________________________
157 Float_t AliPHOSClusterizerv1::CalibrateEMC(Float_t amp, Int_t absId)
159 // Convert EMC measured amplitude into real energy.
160 // Calibration parameters are taken from calibration data base for raw data,
161 // or from digitizer parameters for simulated data.
165 AliPHOSGetter *gime = AliPHOSGetter::Instance();
166 gime->PHOSGeometry()->AbsToRelNumbering(absId,relId) ;
167 Int_t module = relId[0];
168 Int_t column = relId[3];
169 Int_t row = relId[2];
170 if(absId <= fEmcCrystals) { // this is EMC
171 fADCchanelEmc = fCalibData->GetADCchannelEmc (module,column,row);
172 return amp*fADCchanelEmc ;
176 if(absId <= fEmcCrystals) // this is EMC
177 return fADCpedestalEmc + amp*fADCchanelEmc ;
182 //____________________________________________________________________________
183 Float_t AliPHOSClusterizerv1::CalibrateCPV(Int_t amp, Int_t absId)
185 // Convert digitized CPV amplitude into charge.
186 // Calibration parameters are taken from calibration data base for raw data,
187 // or from digitizer parameters for simulated data.
191 AliPHOSGetter *gime = AliPHOSGetter::Instance();
192 gime->PHOSGeometry()->AbsToRelNumbering(absId,relId) ;
193 Int_t module = relId[0];
194 Int_t column = relId[3];
195 Int_t row = relId[2];
196 if(absId > fEmcCrystals) { // this is CPV
197 fADCchanelCpv = fCalibData->GetADCchannelCpv (module,column,row);
198 fADCpedestalCpv = fCalibData->GetADCpedestalCpv(module,column,row);
199 return fADCpedestalCpv + amp*fADCchanelCpv ;
203 if(absId > fEmcCrystals) // this is CPV
204 return fADCpedestalCpv+ amp*fADCchanelCpv ;
209 //____________________________________________________________________________
210 void AliPHOSClusterizerv1::Exec(Option_t *option)
212 // Steering method to perform clusterization for events
213 // in the range from fFirstEvent to fLastEvent.
214 // This range is optionally set by SetEventRange().
215 // if fLastEvent=-1 (by default), then process events until the end.
217 if(strstr(option,"tim"))
218 gBenchmark->Start("PHOSClusterizer");
220 if(strstr(option,"print")) {
225 GetCalibrationParameters() ;
227 AliPHOSGetter * gime = AliPHOSGetter::Instance() ;
229 gime->SetRawDigits(kFALSE);
231 gime->SetRawDigits(kTRUE);
233 if (fLastEvent == -1)
234 fLastEvent = gime->MaxEvent() - 1 ;
236 fLastEvent = TMath::Min(fFirstEvent, gime->MaxEvent()); // one event at the time
237 Int_t nEvents = fLastEvent - fFirstEvent + 1;
240 for (ievent = fFirstEvent; ievent <= fLastEvent; ievent++) {
242 gime->Event(ievent ,"D"); // Read digits from simulated data
244 gime->Event(fRawReader,"W",fIsOldRCUFormat); // Read digits from raw data
246 fNumberOfEmcClusters = fNumberOfCpvClusters = 0 ;
255 if(strstr(option,"deb"))
256 PrintRecPoints(option) ;
258 //increment the total number of recpoints per run
259 fRecPointsInRun += gime->EmcRecPoints()->GetEntriesFast() ;
260 fRecPointsInRun += gime->CpvRecPoints()->GetEntriesFast() ;
263 if(fWrite) //do not unload in "on flight" mode
266 if(strstr(option,"tim")){
267 gBenchmark->Stop("PHOSClusterizer");
268 AliInfo(Form("took %f seconds for Clusterizing %f seconds per event \n",
269 gBenchmark->GetCpuTime("PHOSClusterizer"),
270 gBenchmark->GetCpuTime("PHOSClusterizer")/nEvents )) ;
274 //____________________________________________________________________________
275 Bool_t AliPHOSClusterizerv1::FindFit(AliPHOSEmcRecPoint * emcRP, AliPHOSDigit ** maxAt, Float_t * maxAtEnergy,
276 Int_t nPar, Float_t * fitparameters) const
278 // Calls TMinuit to fit the energy distribution of a cluster with several maxima
279 // The initial values for fitting procedure are set equal to the positions of local maxima.
280 // Cluster will be fitted as a superposition of nPar/3 electromagnetic showers
283 AliPHOSGetter * gime = AliPHOSGetter::Instance();
284 TClonesArray * digits = gime->Digits();
287 gMinuit->mncler(); // Reset Minuit's list of paramters
288 gMinuit->SetPrintLevel(-1) ; // No Printout
289 gMinuit->SetFCN(AliPHOSClusterizerv1::UnfoldingChiSquare) ;
290 // To set the address of the minimization function
292 TList * toMinuit = new TList();
293 toMinuit->AddAt(emcRP,0) ;
294 toMinuit->AddAt(digits,1) ;
296 gMinuit->SetObjectFit(toMinuit) ; // To tranfer pointer to UnfoldingChiSquare
298 // filling initial values for fit parameters
299 AliPHOSDigit * digit ;
303 Int_t nDigits = (Int_t) nPar / 3 ;
307 const AliPHOSGeometry * geom = gime->PHOSGeometry() ;
309 for(iDigit = 0; iDigit < nDigits; iDigit++){
310 digit = maxAt[iDigit];
315 geom->AbsToRelNumbering(digit->GetId(), relid) ;
316 geom->RelPosInModule(relid, x, z) ;
318 Float_t energy = maxAtEnergy[iDigit] ;
320 gMinuit->mnparm(index, "x", x, 0.1, 0, 0, ierflg) ;
323 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : x = %f\n", x ) ;
326 gMinuit->mnparm(index, "z", z, 0.1, 0, 0, ierflg) ;
329 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : z =%f\n", z ) ;
332 gMinuit->mnparm(index, "Energy", energy , 0.05*energy, 0., 4.*energy, ierflg) ;
335 Warning("FindFit", "PHOS Unfolding unable to set initial value for fit procedure : energy = %f\n", energy ) ;
340 Double_t p0 = 0.1 ; // "Tolerance" Evaluation stops when EDM = 0.0001*p0 ; The number of function call slightly
345 gMinuit->mnexcm("SET STR", &p2, 0, ierflg) ; // force TMinuit to reduce function calls
346 gMinuit->mnexcm("SET GRA", &p1, 1, ierflg) ; // force TMinuit to use my gradient
347 gMinuit->SetMaxIterations(5);
348 gMinuit->mnexcm("SET NOW", &p2 , 0, ierflg) ; // No Warnings
350 gMinuit->mnexcm("MIGRAD", &p0, 0, ierflg) ; // minimize
352 if(ierflg == 4){ // Minimum not found
353 Warning("FindFit", "PHOS Unfolding fit not converged, cluster abandoned\n" );
356 for(index = 0; index < nPar; index++){
359 gMinuit->GetParameter(index, val, err) ; // Returns value and error of parameter index
360 fitparameters[index] = val ;
368 //____________________________________________________________________________
369 void AliPHOSClusterizerv1::GetCalibrationParameters()
371 // Set calibration parameters:
372 // if calibration database exists, they are read from database,
373 // otherwise, they are taken from digitizer.
375 // It is a user responsilibity to open CDB before reconstruction, for example:
376 // AliCDBStorage* storage = AliCDBManager::Instance()->GetStorage("local://CalibDB");
378 AliPHOSGetter * gime = AliPHOSGetter::Instance();
379 // fCalibData = new AliPHOSCalibData(gAlice->GetRunNumber()); //original
381 fCalibData = new AliPHOSCalibData(-1); //use AliCDBManager's run number
385 if ( !gime->Digitizer() )
386 gime->LoadDigitizer();
387 AliPHOSDigitizer * dig = gime->Digitizer();
388 fADCchanelEmc = dig->GetEMCchannel() ;
389 fADCpedestalEmc = dig->GetEMCpedestal();
391 fADCchanelCpv = dig->GetCPVchannel() ;
392 fADCpedestalCpv = dig->GetCPVpedestal() ;
396 //____________________________________________________________________________
397 void AliPHOSClusterizerv1::Init()
399 // Make all memory allocations which can not be done in default constructor.
400 // Attach the Clusterizer task to the list of PHOS tasks
402 AliPHOSGetter* gime = AliPHOSGetter::Instance() ;
404 gime = AliPHOSGetter::Instance(GetTitle(), fEventFolderName.Data());
406 AliPHOSGeometry * geom = gime->PHOSGeometry();
408 fEmcCrystals = geom->GetNModules() * geom->GetNCristalsInModule() ;
411 gMinuit = new TMinuit(100);
413 if ( !gime->Clusterizer() ) {
414 gime->PostClusterizer(this);
418 //____________________________________________________________________________
419 void AliPHOSClusterizerv1::InitParameters()
422 fNumberOfCpvClusters = 0 ;
423 fNumberOfEmcClusters = 0 ;
425 fCpvClusteringThreshold = 0.0;
426 fEmcClusteringThreshold = 0.2;
428 fEmcLocMaxCut = 0.03 ;
429 fCpvLocMaxCut = 0.03 ;
437 fEmcTimeGate = 1.e-8 ;
441 fRecPointsInRun = 0 ;
447 SetEventRange(0,-1) ;
449 fIsOldRCUFormat = kFALSE;
452 //____________________________________________________________________________
453 Int_t AliPHOSClusterizerv1::AreNeighbours(AliPHOSDigit * d1, AliPHOSDigit * d2)const
455 // Gives the neighbourness of two digits = 0 are not neighbour but continue searching
457 // = 2 are not neighbour but do not continue searching
458 // neighbours are defined as digits having at least a common vertex
459 // The order of d1 and d2 is important: first (d1) should be a digit already in a cluster
460 // which is compared to a digit (d2) not yet in a cluster
462 AliPHOSGeometry * geom = AliPHOSGetter::Instance()->PHOSGeometry() ;
467 geom->AbsToRelNumbering(d1->GetId(), relid1) ;
470 geom->AbsToRelNumbering(d2->GetId(), relid2) ;
472 if ( (relid1[0] == relid2[0]) && (relid1[1]==relid2[1]) ) { // inside the same PHOS module
473 Int_t rowdiff = TMath::Abs( relid1[2] - relid2[2] ) ;
474 Int_t coldiff = TMath::Abs( relid1[3] - relid2[3] ) ;
476 if (( coldiff <= 1 ) && ( rowdiff <= 1 )){
477 if((relid1[1] != 0) || (TMath::Abs(d1->GetTime() - d2->GetTime() ) < fEmcTimeGate))
481 if((relid2[2] > relid1[2]) && (relid2[3] > relid1[3]+1))
482 rv = 2; // Difference in row numbers is too large to look further
488 if( (relid1[0] < relid2[0]) || (relid1[1] != relid2[1]) )
495 //____________________________________________________________________________
496 void AliPHOSClusterizerv1::CleanDigits(TClonesArray * digits)
498 // Remove digits with amplitudes below threshold
500 for(Int_t i=0; i<digits->GetEntriesFast(); i++){
501 AliPHOSDigit * digit = static_cast<AliPHOSDigit*>(digits->At(i)) ;
502 if ( (IsInEmc(digit) && CalibrateEMC(digit->GetEnergy(),digit->GetId()) < fEmcMinE) ||
503 (IsInCpv(digit) && CalibrateCPV(digit->GetAmp() ,digit->GetId()) < fCpvMinE) )
504 digits->RemoveAt(i) ;
507 for (Int_t i = 0 ; i < digits->GetEntriesFast() ; i++) {
508 AliPHOSDigit *digit = static_cast<AliPHOSDigit*>( digits->At(i) ) ;
509 digit->SetIndexInList(i) ;
513 //____________________________________________________________________________
514 Bool_t AliPHOSClusterizerv1::IsInEmc(AliPHOSDigit * digit) const
516 // Tells if (true) or not (false) the digit is in a PHOS-EMC module
519 AliPHOSGeometry * geom = AliPHOSGetter::Instance()->PHOSGeometry() ;
521 Int_t nEMC = geom->GetNModules()*geom->GetNPhi()*geom->GetNZ();
523 if(digit->GetId() <= nEMC ) rv = kTRUE;
528 //____________________________________________________________________________
529 Bool_t AliPHOSClusterizerv1::IsInCpv(AliPHOSDigit * digit) const
531 // Tells if (true) or not (false) the digit is in a PHOS-CPV module
535 AliPHOSGeometry * geom = AliPHOSGetter::Instance()->PHOSGeometry() ;
537 Int_t nEMC = geom->GetNModules()*geom->GetNPhi()*geom->GetNZ();
539 if(digit->GetId() > nEMC ) rv = kTRUE;
544 //____________________________________________________________________________
545 void AliPHOSClusterizerv1::Unload()
547 AliPHOSGetter * gime = AliPHOSGetter::Instance() ;
548 gime->PhosLoader()->UnloadDigits() ;
549 gime->PhosLoader()->UnloadRecPoints() ;
552 //____________________________________________________________________________
553 void AliPHOSClusterizerv1::WriteRecPoints()
556 // Creates new branches with given title
557 // fills and writes into TreeR.
559 AliPHOSGetter * gime = AliPHOSGetter::Instance();
561 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
562 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
563 TClonesArray * digits = gime->Digits() ;
567 //Evaluate position, dispersion and other RecPoint properties..
568 Int_t nEmc = emcRecPoints->GetEntriesFast();
569 for(index = 0; index < nEmc; index++){
570 AliPHOSEmcRecPoint * rp = dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(index) );
571 rp->Purify(fEmcMinE) ;
572 if(rp->GetMultiplicity()>0.) //If this RP is not empty
573 rp->EvalAll(fW0,digits) ;
575 emcRecPoints->RemoveAt(index) ;
579 emcRecPoints->Compress() ;
580 emcRecPoints->Sort() ;
581 // emcRecPoints->Expand(emcRecPoints->GetEntriesFast()) ;
582 for(index = 0; index < emcRecPoints->GetEntries(); index++){
583 dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(index) )->SetIndexInList(index) ;
586 //Now the same for CPV
587 for(index = 0; index < cpvRecPoints->GetEntries(); index++){
588 AliPHOSCpvRecPoint * rp = dynamic_cast<AliPHOSCpvRecPoint *>( cpvRecPoints->At(index) );
589 rp->EvalAll(fW0CPV,digits) ;
591 cpvRecPoints->Sort() ;
593 for(index = 0; index < cpvRecPoints->GetEntries(); index++)
594 dynamic_cast<AliPHOSCpvRecPoint *>( cpvRecPoints->At(index) )->SetIndexInList(index) ;
596 cpvRecPoints->Expand(cpvRecPoints->GetEntriesFast()) ;
598 if(fWrite){ //We write TreeR
599 TTree * treeR = gime->TreeR();
601 Int_t bufferSize = 32000 ;
602 Int_t splitlevel = 0 ;
605 TBranch * emcBranch = treeR->Branch("PHOSEmcRP","TObjArray",&emcRecPoints,bufferSize,splitlevel);
606 emcBranch->SetTitle(BranchName());
609 TBranch * cpvBranch = treeR->Branch("PHOSCpvRP","TObjArray",&cpvRecPoints,bufferSize,splitlevel);
610 cpvBranch->SetTitle(BranchName());
615 gime->WriteRecPoints("OVERWRITE");
616 gime->WriteClusterizer("OVERWRITE");
620 //____________________________________________________________________________
621 void AliPHOSClusterizerv1::MakeClusters()
623 // Steering method to construct the clusters stored in a list of Reconstructed Points
624 // A cluster is defined as a list of neighbour digits
627 AliPHOSGetter * gime = AliPHOSGetter::Instance();
629 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
630 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
632 emcRecPoints->Delete() ;
633 cpvRecPoints->Delete() ;
635 TClonesArray * digits = gime->Digits() ;
637 //Remove digits below threshold
638 CleanDigits(digits) ;
640 TClonesArray * digitsC = static_cast<TClonesArray*>( digits->Clone() ) ;
642 // Clusterization starts
644 TIter nextdigit(digitsC) ;
645 AliPHOSDigit * digit ;
646 Bool_t notremoved = kTRUE ;
648 while ( (digit = dynamic_cast<AliPHOSDigit *>( nextdigit()) ) ) { // scan over the list of digitsC
651 AliPHOSRecPoint * clu = 0 ;
653 TArrayI clusterdigitslist(1500) ;
656 if (( IsInEmc (digit) &&
657 CalibrateEMC(digit->GetEnergy(),digit->GetId()) > fEmcClusteringThreshold ) ||
659 CalibrateCPV(digit->GetAmp() ,digit->GetId()) > fCpvClusteringThreshold ) ) {
660 Int_t iDigitInCluster = 0 ;
662 if ( IsInEmc(digit) ) {
663 // start a new EMC RecPoint
664 if(fNumberOfEmcClusters >= emcRecPoints->GetSize())
665 emcRecPoints->Expand(2*fNumberOfEmcClusters+1) ;
667 emcRecPoints->AddAt(new AliPHOSEmcRecPoint(""), fNumberOfEmcClusters) ;
668 clu = dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(fNumberOfEmcClusters) ) ;
669 fNumberOfEmcClusters++ ;
670 clu->AddDigit(*digit, CalibrateEMC(digit->GetEnergy(),digit->GetId())) ;
671 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
673 digitsC->Remove(digit) ;
677 // start a new CPV cluster
678 if(fNumberOfCpvClusters >= cpvRecPoints->GetSize())
679 cpvRecPoints->Expand(2*fNumberOfCpvClusters+1);
681 cpvRecPoints->AddAt(new AliPHOSCpvRecPoint(""), fNumberOfCpvClusters) ;
683 clu = dynamic_cast<AliPHOSCpvRecPoint *>( cpvRecPoints->At(fNumberOfCpvClusters) ) ;
684 fNumberOfCpvClusters++ ;
685 clu->AddDigit(*digit, CalibrateCPV(digit->GetAmp(),digit->GetId()) ) ;
686 clusterdigitslist[iDigitInCluster] = digit->GetIndexInList() ;
688 digitsC->Remove(digit) ;
691 // Here we remove remaining EMC digits, which cannot make a cluster
694 while( ( digit = dynamic_cast<AliPHOSDigit *>( nextdigit() ) ) ) {
696 digitsC->Remove(digit) ;
700 notremoved = kFALSE ;
707 AliPHOSDigit * digitN ;
709 while (index < iDigitInCluster){ // scan over digits already in cluster
710 digit = dynamic_cast<AliPHOSDigit*>( digits->At(clusterdigitslist[index]) ) ;
712 while ( (digitN = dynamic_cast<AliPHOSDigit *>( nextdigit() ) ) ) { // scan over the reduced list of digits
713 Int_t ineb = AreNeighbours(digit, digitN); // call (digit,digitN) in THAT oder !!!!!
715 case 0 : // not a neighbour
717 case 1 : // are neighbours
718 if (IsInEmc (digitN))
719 clu->AddDigit(*digitN, CalibrateEMC( digitN->GetEnergy(), digitN->GetId() ) );
721 clu->AddDigit(*digitN, CalibrateCPV( digitN->GetAmp() , digitN->GetId() ) );
723 clusterdigitslist[iDigitInCluster] = digitN->GetIndexInList() ;
725 digitsC->Remove(digitN) ;
727 case 2 : // too far from each other
736 } // loop over cluster
747 //____________________________________________________________________________
748 void AliPHOSClusterizerv1::MakeUnfolding()
750 // Unfolds clusters using the shape of an ElectroMagnetic shower
751 // Performs unfolding of all EMC/CPV clusters
753 AliPHOSGetter * gime = AliPHOSGetter::Instance();
755 const AliPHOSGeometry * geom = gime->PHOSGeometry() ;
757 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
758 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
759 TClonesArray * digits = gime->Digits() ;
761 // Unfold first EMC clusters
762 if(fNumberOfEmcClusters > 0){
764 Int_t nModulesToUnfold = geom->GetNModules() ;
766 Int_t numberofNotUnfolded = fNumberOfEmcClusters ;
768 for(index = 0 ; index < numberofNotUnfolded ; index++){
770 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(index) ) ;
771 if(emcRecPoint->GetPHOSMod()> nModulesToUnfold)
774 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
775 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
776 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
777 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fEmcLocMaxCut,digits) ;
779 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
780 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
781 emcRecPoints->Remove(emcRecPoint);
782 emcRecPoints->Compress() ;
784 fNumberOfEmcClusters -- ;
785 numberofNotUnfolded-- ;
788 emcRecPoint->SetNExMax(1) ; //Only one local maximum
792 delete[] maxAtEnergy ;
795 // Unfolding of EMC clusters finished
798 // Unfold now CPV clusters
799 if(fNumberOfCpvClusters > 0){
801 Int_t nModulesToUnfold = geom->GetNModules() ;
803 Int_t numberofCpvNotUnfolded = fNumberOfCpvClusters ;
805 for(index = 0 ; index < numberofCpvNotUnfolded ; index++){
807 AliPHOSRecPoint * recPoint = dynamic_cast<AliPHOSRecPoint *>( cpvRecPoints->At(index) ) ;
809 if(recPoint->GetPHOSMod()> nModulesToUnfold)
812 AliPHOSEmcRecPoint * emcRecPoint = dynamic_cast<AliPHOSEmcRecPoint*>(recPoint) ;
814 Int_t nMultipl = emcRecPoint->GetMultiplicity() ;
815 AliPHOSDigit ** maxAt = new AliPHOSDigit*[nMultipl] ;
816 Float_t * maxAtEnergy = new Float_t[nMultipl] ;
817 Int_t nMax = emcRecPoint->GetNumberOfLocalMax(maxAt, maxAtEnergy,fCpvLocMaxCut,digits) ;
819 if( nMax > 1 ) { // if cluster is very flat (no pronounced maximum) then nMax = 0
820 UnfoldCluster(emcRecPoint, nMax, maxAt, maxAtEnergy) ;
821 cpvRecPoints->Remove(emcRecPoint);
822 cpvRecPoints->Compress() ;
824 numberofCpvNotUnfolded-- ;
825 fNumberOfCpvClusters-- ;
829 delete[] maxAtEnergy ;
832 //Unfolding of Cpv clusters finished
836 //____________________________________________________________________________
837 Double_t AliPHOSClusterizerv1::ShowerShape(Double_t r)
839 // Shape of the shower (see PHOS TDR)
840 // If you change this function, change also the gradient evaluation in ChiSquare()
842 Double_t r4 = r*r*r*r ;
843 Double_t r295 = TMath::Power(r, 2.95) ;
844 Double_t shape = TMath::Exp( -r4 * (1. / (2.32 + 0.26 * r4) + 0.0316 / (1 + 0.0652 * r295) ) ) ;
848 //____________________________________________________________________________
849 void AliPHOSClusterizerv1::UnfoldCluster(AliPHOSEmcRecPoint * iniEmc,
851 AliPHOSDigit ** maxAt,
852 Float_t * maxAtEnergy)
854 // Performs the unfolding of a cluster with nMax overlapping showers
856 AliPHOSGetter * gime = AliPHOSGetter::Instance();
858 const AliPHOSGeometry * geom = gime->PHOSGeometry() ;
860 const TClonesArray * digits = gime->Digits() ;
861 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
862 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
864 Int_t nPar = 3 * nMax ;
865 Float_t * fitparameters = new Float_t[nPar] ;
867 Bool_t rv = FindFit(iniEmc, maxAt, maxAtEnergy, nPar, fitparameters) ;
869 // Fit failed, return and remove cluster
870 iniEmc->SetNExMax(-1) ;
871 delete[] fitparameters ;
875 // create ufolded rec points and fill them with new energy lists
876 // First calculate energy deposited in each sell in accordance with fit (without fluctuations): efit[]
877 // and later correct this number in acordance with actual energy deposition
879 Int_t nDigits = iniEmc->GetMultiplicity() ;
880 Float_t * efit = new Float_t[nDigits] ;
881 Float_t xDigit=0.,zDigit=0.,distance=0. ;
882 Float_t xpar=0.,zpar=0.,epar=0. ;
884 AliPHOSDigit * digit = 0 ;
885 Int_t * emcDigits = iniEmc->GetDigitsList() ;
889 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
890 digit = dynamic_cast<AliPHOSDigit*>( digits->At(emcDigits[iDigit] ) ) ;
891 geom->AbsToRelNumbering(digit->GetId(), relid) ;
892 geom->RelPosInModule(relid, xDigit, zDigit) ;
896 while(iparam < nPar ){
897 xpar = fitparameters[iparam] ;
898 zpar = fitparameters[iparam+1] ;
899 epar = fitparameters[iparam+2] ;
901 distance = (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) ;
902 distance = TMath::Sqrt(distance) ;
903 efit[iDigit] += epar * ShowerShape(distance) ;
908 // Now create new RecPoints and fill energy lists with efit corrected to fluctuations
909 // so that energy deposited in each cell is distributed betwin new clusters proportionally
910 // to its contribution to efit
912 Float_t * emcEnergies = iniEmc->GetEnergiesList() ;
916 while(iparam < nPar ){
917 xpar = fitparameters[iparam] ;
918 zpar = fitparameters[iparam+1] ;
919 epar = fitparameters[iparam+2] ;
922 AliPHOSEmcRecPoint * emcRP = 0 ;
924 if(iniEmc->IsEmc()){ //create new entries in fEmcRecPoints...
926 if(fNumberOfEmcClusters >= emcRecPoints->GetSize())
927 emcRecPoints->Expand(2*fNumberOfEmcClusters) ;
929 (*emcRecPoints)[fNumberOfEmcClusters] = new AliPHOSEmcRecPoint("") ;
930 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( emcRecPoints->At(fNumberOfEmcClusters) ) ;
931 fNumberOfEmcClusters++ ;
932 emcRP->SetNExMax((Int_t)nPar/3) ;
934 else{//create new entries in fCpvRecPoints
935 if(fNumberOfCpvClusters >= cpvRecPoints->GetSize())
936 cpvRecPoints->Expand(2*fNumberOfCpvClusters) ;
938 (*cpvRecPoints)[fNumberOfCpvClusters] = new AliPHOSCpvRecPoint("") ;
939 emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( cpvRecPoints->At(fNumberOfCpvClusters) ) ;
940 fNumberOfCpvClusters++ ;
944 for(iDigit = 0 ; iDigit < nDigits ; iDigit ++){
945 digit = dynamic_cast<AliPHOSDigit*>( digits->At( emcDigits[iDigit] ) ) ;
946 geom->AbsToRelNumbering(digit->GetId(), relid) ;
947 geom->RelPosInModule(relid, xDigit, zDigit) ;
948 distance = (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) ;
949 distance = TMath::Sqrt(distance) ;
950 ratio = epar * ShowerShape(distance) / efit[iDigit] ;
951 eDigit = emcEnergies[iDigit] * ratio ;
952 emcRP->AddDigit( *digit, eDigit ) ;
956 delete[] fitparameters ;
961 //_____________________________________________________________________________
962 void AliPHOSClusterizerv1::UnfoldingChiSquare(Int_t & nPar, Double_t * Grad, Double_t & fret, Double_t * x, Int_t iflag)
964 // Calculates the Chi square for the cluster unfolding minimization
965 // Number of parameters, Gradient, Chi squared, parameters, what to do
967 TList * toMinuit = dynamic_cast<TList*>( gMinuit->GetObjectFit() ) ;
969 AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint*>( toMinuit->At(0) ) ;
970 TClonesArray * digits = dynamic_cast<TClonesArray*>( toMinuit->At(1) ) ;
974 // AliPHOSEmcRecPoint * emcRP = dynamic_cast<AliPHOSEmcRecPoint *>( gMinuit->GetObjectFit() ) ; // EmcRecPoint to fit
976 Int_t * emcDigits = emcRP->GetDigitsList() ;
978 Int_t nOdigits = emcRP->GetDigitsMultiplicity() ;
980 Float_t * emcEnergies = emcRP->GetEnergiesList() ;
982 const AliPHOSGeometry * geom = AliPHOSGetter::Instance()->PHOSGeometry() ;
987 for(iparam = 0 ; iparam < nPar ; iparam++)
988 Grad[iparam] = 0 ; // Will evaluate gradient
992 AliPHOSDigit * digit ;
995 for( iDigit = 0 ; iDigit < nOdigits ; iDigit++) {
997 digit = dynamic_cast<AliPHOSDigit*>( digits->At( emcDigits[iDigit] ) );
1003 geom->AbsToRelNumbering(digit->GetId(), relid) ;
1005 geom->RelPosInModule(relid, xDigit, zDigit) ;
1007 if(iflag == 2){ // calculate gradient
1010 while(iParam < nPar ){
1011 Double_t distance = (xDigit - x[iParam]) * (xDigit - x[iParam]) ;
1013 distance += (zDigit - x[iParam]) * (zDigit - x[iParam]) ;
1014 distance = TMath::Sqrt( distance ) ;
1016 efit += x[iParam] * ShowerShape(distance) ;
1019 Double_t sum = 2. * (efit - emcEnergies[iDigit]) / emcEnergies[iDigit] ; // Here we assume, that sigma = sqrt(E)
1021 while(iParam < nPar ){
1022 Double_t xpar = x[iParam] ;
1023 Double_t zpar = x[iParam+1] ;
1024 Double_t epar = x[iParam+2] ;
1025 Double_t dr = TMath::Sqrt( (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) );
1026 Double_t shape = sum * ShowerShape(dr) ;
1027 Double_t r4 = dr*dr*dr*dr ;
1028 Double_t r295 = TMath::Power(dr,2.95) ;
1029 Double_t deriv =-4. * dr*dr * ( 2.32 / ( (2.32 + 0.26 * r4) * (2.32 + 0.26 * r4) ) +
1030 0.0316 * (1. + 0.0171 * r295) / ( ( 1. + 0.0652 * r295) * (1. + 0.0652 * r295) ) ) ;
1032 Grad[iParam] += epar * shape * deriv * (xpar - xDigit) ; // Derivative over x
1034 Grad[iParam] += epar * shape * deriv * (zpar - zDigit) ; // Derivative over z
1036 Grad[iParam] += shape ; // Derivative over energy
1043 while(iparam < nPar ){
1044 Double_t xpar = x[iparam] ;
1045 Double_t zpar = x[iparam+1] ;
1046 Double_t epar = x[iparam+2] ;
1048 Double_t distance = (xDigit - xpar) * (xDigit - xpar) + (zDigit - zpar) * (zDigit - zpar) ;
1049 distance = TMath::Sqrt(distance) ;
1050 efit += epar * ShowerShape(distance) ;
1053 fret += (efit-emcEnergies[iDigit])*(efit-emcEnergies[iDigit])/emcEnergies[iDigit] ;
1054 // Here we assume, that sigma = sqrt(E)
1059 //____________________________________________________________________________
1060 void AliPHOSClusterizerv1::Print(const Option_t *)const
1062 // Print clusterizer parameters
1065 TString taskName(GetName()) ;
1066 taskName.ReplaceAll(Version(), "") ;
1068 if( strcmp(GetName(), "") !=0 ) {
1070 message = "\n--------------- %s %s -----------\n" ;
1071 message += "Clusterizing digits from the file: %s\n" ;
1072 message += " Branch: %s\n" ;
1073 message += " EMC Clustering threshold = %f\n" ;
1074 message += " EMC Local Maximum cut = %f\n" ;
1075 message += " EMC Logarothmic weight = %f\n" ;
1076 message += " CPV Clustering threshold = %f\n" ;
1077 message += " CPV Local Maximum cut = %f\n" ;
1078 message += " CPV Logarothmic weight = %f\n" ;
1080 message += " Unfolding on\n" ;
1082 message += " Unfolding off\n" ;
1084 message += "------------------------------------------------------------------" ;
1087 message = " AliPHOSClusterizerv1 not initialized " ;
1089 AliInfo(Form("%s, %s %s %s %s %s %s %s %s %s %s", message.Data(),
1094 fEmcClusteringThreshold,
1097 fCpvClusteringThreshold,
1103 //____________________________________________________________________________
1104 void AliPHOSClusterizerv1::PrintRecPoints(Option_t * option)
1106 // Prints list of RecPoints produced at the current pass of AliPHOSClusterizer
1108 AliPHOSGetter * gime = AliPHOSGetter::Instance();
1110 TObjArray * emcRecPoints = gime->EmcRecPoints() ;
1111 TObjArray * cpvRecPoints = gime->CpvRecPoints() ;
1113 AliInfo(Form("\nevent %d \n Found %d EMC RecPoints and %d CPV RecPoints",
1114 gAlice->GetEvNumber(),
1115 emcRecPoints->GetEntriesFast(),
1116 cpvRecPoints->GetEntriesFast() )) ;
1118 fRecPointsInRun += emcRecPoints->GetEntriesFast() ;
1119 fRecPointsInRun += cpvRecPoints->GetEntriesFast() ;
1122 if(strstr(option,"all")) {
1123 printf("\n EMC clusters \n") ;
1124 printf("Index Ene(MeV) Multi Module X Y Z Lambdas_1 Lambda_2 # of prim Primaries list\n") ;
1126 for (index = 0 ; index < emcRecPoints->GetEntries() ; index++) {
1127 AliPHOSEmcRecPoint * rp = (AliPHOSEmcRecPoint * )emcRecPoints->At(index) ;
1129 rp->GetLocalPosition(locpos);
1131 rp->GetElipsAxis(lambda);
1134 primaries = rp->GetPrimaries(nprimaries);
1135 printf("\n%6d %8.2f %3d %2d %4.1f %4.1f %4.1f %4f %4f %2d : ",
1136 rp->GetIndexInList(), rp->GetEnergy(), rp->GetMultiplicity(), rp->GetPHOSMod(),
1137 locpos.X(), locpos.Y(), locpos.Z(), lambda[0], lambda[1], nprimaries) ;
1139 for (Int_t iprimary=0; iprimary<nprimaries; iprimary++) {
1140 printf("%d ", primaries[iprimary] ) ;
1145 //Now plot CPV recPoints
1146 printf("\n CPV clusters \n") ;
1147 printf("Index Ene(MeV) Module X Y Z \n") ;
1148 for (index = 0 ; index < cpvRecPoints->GetEntries() ; index++) {
1149 AliPHOSCpvRecPoint * rp = (AliPHOSCpvRecPoint * )cpvRecPoints->At(index) ;
1152 rp->GetLocalPosition(locpos);
1154 printf("\n%6d %8.2f %2d %4.1f %4.1f %4.1f \n",
1155 rp->GetIndexInList(), rp->GetEnergy(), rp->GetPHOSMod(),
1156 locpos.X(), locpos.Y(), locpos.Z()) ;