2 // Original: AliHLTClustFinderNew.cxx,v 1.29 2005/06/14 10:55:21 cvetan Exp
4 //**************************************************************************
5 //* This file is property of and copyright by the ALICE HLT Project *
6 //* ALICE Experiment at CERN, All rights reserved. *
8 //* Primary Authors: Anders Vestbo, Constantin Loizides *
9 //* Developers: Kenneth Aamodt <kenneth.aamodt@student.uib.no> *
11 //* for The ALICE HLT Project. *
13 //* Permission to use, copy, modify and distribute this software and its *
14 //* documentation strictly for non-commercial purposes is hereby granted *
15 //* without fee, provided that the above copyright notice appears in all *
16 //* copies and that both the copyright notice and this permission notice *
17 //* appear in the supporting documentation. The authors make no claims *
18 //* about the suitability of this software for any purpose. It is *
19 //* provided "as is" without express or implied warranty. *
20 //**************************************************************************
22 /** @file AliHLTTPCClusterFinder.cxx
23 @author Kenneth Aamodt, Kalliopi Kanaki
25 @brief Cluster Finder for the TPC
28 #include "AliHLTTPCDigitReader.h"
29 #include "AliHLTTPCRootTypes.h"
30 #include "AliHLTTPCLogging.h"
31 #include "AliHLTTPCClusterFinder.h"
32 #include "AliHLTTPCSpacePointData.h"
33 #include "AliHLTTPCMemHandler.h"
34 #include "AliHLTTPCPad.h"
38 #include "AliTPCcalibDB.h"
39 #include "AliTPCTransform.h"
45 ClassImp(AliHLTTPCClusterFinder)
47 AliHLTTPCClusterFinder::AliHLTTPCClusterFinder()
49 fClustersHWAddressVector(),
51 fSpacePointData(NULL),
73 fVectorInitialized(kFALSE),
77 fNumberOfPadsInRow(NULL),
79 fRowOfFirstCandidate(0),
80 fDoPadSelection(kFALSE),
82 fLastTimeBin(AliHLTTPCTransform::GetNTimeBins()),
83 fTotalChargeOfPreviousClusterCandidate(0),
84 fChargeOfCandidatesFalling(kFALSE),
88 fOfflineTransform(NULL),
89 fOfflineTPCRecoParam(),
94 fOfflineTransform = AliTPCcalibDB::Instance()->GetTransform();
95 if(!fOfflineTransform){
96 HLTError("AliHLTTPCClusterFinder(): Offline transform not in AliTPCcalibDB.");
99 fOfflineTPCRecoParam.SetUseExBCorrection(1);
100 fOfflineTPCRecoParam.SetUseTOFCorrection(1);
101 fOfflineTransform->SetCurrentRecoParam(&fOfflineTPCRecoParam);
105 AliHLTTPCClusterFinder::~AliHLTTPCClusterFinder(){
106 // see header file for class documentation
109 if(fVectorInitialized){
110 DeInitializePadArray();
112 if(fNumberOfPadsInRow){
113 delete [] fNumberOfPadsInRow;
114 fNumberOfPadsInRow=NULL;
118 void AliHLTTPCClusterFinder::InitSlice(Int_t slice,Int_t patch,Int_t nmaxpoints){
119 // see header file for class documentation
123 fMaxNClusters = nmaxpoints;
124 fCurrentSlice = slice;
125 fCurrentPatch = patch;
126 fFirstRow=AliHLTTPCTransform::GetFirstRow(patch);
127 fLastRow=AliHLTTPCTransform::GetLastRow(patch);
130 fClustersMCInfo.clear();
132 fClusterMCVector.clear();
135 void AliHLTTPCClusterFinder::InitializePadArray(){
136 // see header file for class documentation
138 if(fCurrentPatch>5||fCurrentPatch<0){
139 HLTFatal("Patch is not set");
143 HLTDebug("Patch number=%d",fCurrentPatch);
145 fFirstRow = AliHLTTPCTransform::GetFirstRow(fCurrentPatch);
146 fLastRow = AliHLTTPCTransform::GetLastRow(fCurrentPatch);
148 fNumberOfRows=fLastRow-fFirstRow+1;
149 fNumberOfPadsInRow= new UInt_t[fNumberOfRows];
151 memset( fNumberOfPadsInRow, 0, sizeof(Int_t)*(fNumberOfRows));
153 fRowPadVector.clear();
155 for(UInt_t i=0;i<fNumberOfRows;i++){
156 fNumberOfPadsInRow[i]=AliHLTTPCTransform::GetNPads(i+fFirstRow);
157 AliHLTTPCPadVector tmpRow;
158 for(UInt_t j=0;j<=fNumberOfPadsInRow[i];j++){
159 AliHLTTPCPad *tmpPad = new AliHLTTPCPad(2);
161 tmpRow.push_back(tmpPad);
163 fRowPadVector.push_back(tmpRow);
165 fVectorInitialized=kTRUE;
168 Int_t AliHLTTPCClusterFinder::DeInitializePadArray(){
169 // see header file for class documentation
171 if( fVectorInitialized ){
172 for(UInt_t i=0;i<fNumberOfRows;i++){
173 for(UInt_t j=0;j<=fNumberOfPadsInRow[i];j++){
174 delete fRowPadVector[i][j];
175 fRowPadVector[i][j]=NULL;
177 fRowPadVector[i].clear();
179 fRowPadVector.clear();
180 delete[] fNumberOfPadsInRow;
181 fNumberOfPadsInRow = 0;
183 fVectorInitialized=kFALSE;
188 void AliHLTTPCClusterFinder::SetOutputArray(AliHLTTPCSpacePointData *pt){
189 // see header file for class documentation
190 //set pointer to output
191 fSpacePointData = pt;
195 void AliHLTTPCClusterFinder::ReadDataUnsorted(void* ptr,unsigned long size){
196 // see header file for class documentation
198 fPtr = (UChar_t*)ptr;
201 if(!fVectorInitialized){
202 InitializePadArray();
205 if (fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice)<0) {
206 HLTError("failed setting up digit reader (InitBlock)");
210 while(fDigitReader->NextChannel()){
211 UInt_t row=fDigitReader->GetRow();
212 UInt_t pad=fDigitReader->GetPad();
214 if(row>=fRowPadVector.size()){
215 HLTError("Row number is to large: %d, max is %d",row,fRowPadVector.size()-1);
218 if(pad>=fRowPadVector[row].size()){
219 HLTError("Pad number is to large: %d, max is %d",pad,fRowPadVector[row].size());
223 while(fDigitReader->NextBunch()){
224 if(fDigitReader->GetBunchSize()>1){//to remove single timebin values, this will have to change at some point
225 UInt_t time = fDigitReader->GetTime();
226 if((Int_t)time>=fFirstTimeBin && (Int_t)time+fDigitReader->GetBunchSize()<=fLastTimeBin){
227 // Kenneth: 20-04-09. The following if have been added because of inconsistency in the 40 bit decoder and the 32 bit decoder.
228 // GetSignals() in the 40 bit decoder returns an array of UInt_t while the 32 bit one returns UShort_t
229 // The same is true for the function ReadDataUnsortedDeconvoluteTime() below.
230 // In addition the signals are organized in the opposite direction
232 const UShort_t *bunchData= fDigitReader->GetSignalsShort();
233 AliHLTTPCClusters candidate;
234 for(Int_t i=fDigitReader->GetBunchSize()-1;i>=0;i--){
235 candidate.fTotalCharge+=bunchData[i];
236 candidate.fTime += time*bunchData[i];
237 candidate.fTime2 += time*time*bunchData[i];
238 if(bunchData[i]>candidate.fQMax){
239 candidate.fQMax=bunchData[i];
243 if(candidate.fTotalCharge>0){
244 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
245 candidate.fPad=candidate.fTotalCharge*pad;
246 candidate.fPad2=candidate.fPad*pad;
247 candidate.fLastMergedPad=pad;
248 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
250 if(fRowPadVector[row][pad] != NULL){
251 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
255 const UInt_t *bunchData= fDigitReader->GetSignals();
256 AliHLTTPCClusters candidate;
257 const AliHLTTPCDigitData* digits = NULL;
258 if(fDoMC && (digits = fDigitReader->GetBunchDigits())!=NULL){
259 for(Int_t i=0;i<fDigitReader->GetBunchSize();i++){
260 candidate.fTotalCharge+=bunchData[i];
261 candidate.fTime += time*bunchData[i];
262 candidate.fTime2 += time*time*bunchData[i];
263 if(bunchData[i]>candidate.fQMax){
264 candidate.fQMax=bunchData[i];
266 fMCDigits.push_back(digits[i]);
271 for(Int_t i=0;i<fDigitReader->GetBunchSize();i++){
272 candidate.fTotalCharge+=bunchData[i];
273 candidate.fTime += time*bunchData[i];
274 candidate.fTime2 += time*time*bunchData[i];
275 if(bunchData[i]>candidate.fQMax){
276 candidate.fQMax=bunchData[i];
281 if(candidate.fTotalCharge>0){
282 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
283 candidate.fPad=candidate.fTotalCharge*pad;
284 candidate.fPad2=candidate.fPad*pad;
285 candidate.fLastMergedPad=pad;
286 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
288 if(fRowPadVector[row][pad] != NULL){
289 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
291 fRowPadVector[row][pad]->AddCandidateDigits(fMCDigits);
302 void AliHLTTPCClusterFinder::ReadDataUnsortedDeconvoluteTime(void* ptr,unsigned long size){
303 // see header file for class documentation
306 fPtr = (UChar_t*)ptr;
309 if(!fVectorInitialized){
310 InitializePadArray();
313 if (fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice)<0) {
314 HLTError("failed setting up digit reader (InitBlock)");
318 while(fDigitReader->NextChannel()){
319 UInt_t row=fDigitReader->GetRow();
320 UInt_t pad=fDigitReader->GetPad();
322 while(fDigitReader->NextBunch()){
323 if(fDigitReader->GetBunchSize()>1){//to remove single timebin values, this will have to change at some point
324 UInt_t time = fDigitReader->GetTime();
325 if((Int_t)time>=fFirstTimeBin && (Int_t)time+fDigitReader->GetBunchSize()<=fLastTimeBin){
326 Int_t indexInBunchData=0;
327 Bool_t moreDataInBunch=kFALSE;
329 Bool_t signalFalling=kFALSE;
331 // Kenneth: 20-04-09. The following if have been added because of inconsistency in the 40 bit decoder and the 32 bit decoder.
332 // GetSignals() in the 40 bit decoder returns an array of UInt_t while the 32 bit one returns UShort_t
333 // The same is true for the function ReadDataUnsorted() above.
334 // In addition the signals are organized in the opposite direction
336 indexInBunchData = fDigitReader->GetBunchSize();
337 const UShort_t *bunchData= fDigitReader->GetSignalsShort();
340 AliHLTTPCClusters candidate;
341 //for(Int_t i=indexInBunchData;i<fDigitReader->GetBunchSize();i++){
342 for(Int_t i=indexInBunchData;i>=0;i--){
343 // Checks if one need to deconvolute the signals
344 if(bunchData[i]>prevSignal && signalFalling==kTRUE){
345 if(i<fDigitReader->GetBunchSize()-1){ // means there are more than one signal left in the bunch
346 moreDataInBunch=kTRUE;
352 // Checks if the signal is 0, then quit processing the data.
353 if(bunchData[i]==0 && i<fDigitReader->GetBunchSize()-1){//means we have 0 data fom the rcu, might happen depending on the configuration settings
354 moreDataInBunch=kTRUE;
359 if(prevSignal>bunchData[i]){//means the peak of the signal has been reached and deconvolution will happen if the signal rise again.
362 candidate.fTotalCharge+=bunchData[i];
363 candidate.fTime += time*bunchData[i];
364 candidate.fTime2 += time*time*bunchData[i];
365 if(bunchData[i]>candidate.fQMax){
366 candidate.fQMax=bunchData[i];
369 prevSignal=bunchData[i];
373 if(candidate.fTotalCharge>0){
374 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
375 candidate.fPad=candidate.fTotalCharge*pad;
376 candidate.fPad2=candidate.fPad*pad;
377 candidate.fLastMergedPad=pad;
378 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
380 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
381 fRowPadVector[row][pad]->AddCandidateDigits(fMCDigits);
382 if(indexInBunchData<fDigitReader->GetBunchSize()-1){
383 moreDataInBunch=kFALSE;
385 }while(moreDataInBunch);
388 const UInt_t *bunchData= fDigitReader->GetSignals();
390 AliHLTTPCClusters candidate;
391 for(Int_t i=indexInBunchData;i<fDigitReader->GetBunchSize();i++){
392 // Checks if one need to deconvolute the signals
393 if(bunchData[i]>prevSignal && signalFalling==kTRUE){
394 if(i<fDigitReader->GetBunchSize()-1){ // means there are more than one signal left in the bunch
395 moreDataInBunch=kTRUE;
401 // Checks if the signal is 0, then quit processing the data.
402 if(bunchData[i]==0 && i<fDigitReader->GetBunchSize()-1){//means we have 0 data fom the rcu, might happen depending on the configuration settings
403 moreDataInBunch=kTRUE;
408 if(prevSignal>bunchData[i]){//means the peak of the signal has been reached and deconvolution will happen if the signal rise again.
412 candidate.fTotalCharge+=bunchData[i];
413 candidate.fTime += time*bunchData[i];
414 candidate.fTime2 += time*time*bunchData[i];
415 if(bunchData[i]>candidate.fQMax){
416 candidate.fQMax=bunchData[i];
419 prevSignal=bunchData[i];
423 if(candidate.fTotalCharge>0){
424 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
425 candidate.fPad=candidate.fTotalCharge*pad;
426 candidate.fPad2=candidate.fPad*pad;
427 candidate.fLastMergedPad=pad;
428 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
430 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
431 if(indexInBunchData<fDigitReader->GetBunchSize()-1){
432 moreDataInBunch=kFALSE;
434 }while(moreDataInBunch);
442 Bool_t AliHLTTPCClusterFinder::ComparePads(AliHLTTPCPad *nextPad,AliHLTTPCClusters* cluster,Int_t nextPadToRead){
443 // see header file for class documentation
445 //Checking if we have a match on the next pad
446 for(UInt_t candidateNumber=0;candidateNumber<nextPad->fClusterCandidates.size();candidateNumber++){
447 if(nextPad->fUsedClusterCandidates[candidateNumber] == 1){
450 AliHLTTPCClusters *candidate =&nextPad->fClusterCandidates[candidateNumber];
451 // if(cluster->fMean-candidate->fMean==1 || candidate->fMean-cluster->fMean==1 || cluster->fMean-candidate->fMean==0){
453 if( abs((Int_t)(cluster->fMean - candidate->fMean)) <= fTimeMeanDiff ){
455 if(candidate->fTotalCharge<fTotalChargeOfPreviousClusterCandidate){//peak is reached
456 fChargeOfCandidatesFalling=kTRUE;
458 if(candidate->fTotalCharge>fTotalChargeOfPreviousClusterCandidate && fChargeOfCandidatesFalling==kTRUE){//we have deconvolution
462 cluster->fMean=candidate->fMean;
463 cluster->fTotalCharge+=candidate->fTotalCharge;
464 cluster->fTime += candidate->fTime;
465 cluster->fTime2 += candidate->fTime2;
466 cluster->fPad+=candidate->fPad;
467 cluster->fPad2+=candidate->fPad2;
468 cluster->fLastMergedPad=candidate->fPad;
469 if(candidate->fQMax>cluster->fQMax){
470 cluster->fQMax=candidate->fQMax;
473 FillMCClusterVector(nextPad->GetCandidateDigits(candidateNumber));
477 UInt_t rowNo = nextPad->GetRowNumber();
478 UInt_t padNo = nextPad->GetPadNumber();
480 fRowPadVector[rowNo][padNo-2]->fSelectedPad=kTRUE;
481 fRowPadVector[rowNo][padNo-2]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo-2);
483 fRowPadVector[rowNo][padNo-1]->fSelectedPad=kTRUE;// quick solution to set the first pad to selected
484 fRowPadVector[rowNo][padNo-1]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo-1);
485 fRowPadVector[rowNo][padNo]->fSelectedPad=kTRUE;
486 fRowPadVector[rowNo][padNo]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo);
489 //setting the matched pad to used
490 nextPad->fUsedClusterCandidates[candidateNumber]=1;
492 if(nextPadToRead<(Int_t)fNumberOfPadsInRow[fRowOfFirstCandidate]){
493 nextPad=fRowPadVector[fRowOfFirstCandidate][nextPadToRead];
494 ComparePads(nextPad,cluster,nextPadToRead);
504 Int_t AliHLTTPCClusterFinder::FillHWAddressList(AliHLTUInt16_t *hwaddlist, Int_t maxHWadd){
505 // see header file for class documentation
508 for(UInt_t row=0;row<fNumberOfRows;row++){
509 for(UInt_t pad=0;pad<fNumberOfPadsInRow[row]-1;pad++){
510 if(fRowPadVector[row][pad]->fSelectedPad){
511 if(counter<maxHWadd){
512 hwaddlist[counter]=(AliHLTUInt16_t)fRowPadVector[row][pad]->fHWAddress;
516 HLTWarning("To many hardwareaddresses, skip adding");
526 Int_t AliHLTTPCClusterFinder::FillOutputMCInfo(AliHLTTPCClusterFinder::ClusterMCInfo * outputMCInfo, Int_t maxNumberOfClusterMCInfo){
527 // see header file for class documentation
531 for(UInt_t mc=0;mc<fClustersMCInfo.size();mc++){
532 if(counter<maxNumberOfClusterMCInfo){
533 outputMCInfo[counter] = fClustersMCInfo[mc];
537 HLTWarning("To much MCInfo has been added (no more space), skip adding");
543 void AliHLTTPCClusterFinder::FindClusters(){
544 // see header file for function documentation
546 AliHLTTPCClusters* tmpCandidate=NULL;
547 for(UInt_t row=0;row<fNumberOfRows;row++){
548 fRowOfFirstCandidate=row;
549 for(UInt_t pad=0;pad<fNumberOfPadsInRow[row];pad++){
550 AliHLTTPCPad *tmpPad=fRowPadVector[row][pad];
551 for(size_t candidate=0;candidate<tmpPad->fClusterCandidates.size();candidate++){
552 if(tmpPad->fUsedClusterCandidates[candidate]){
555 tmpCandidate=&tmpPad->fClusterCandidates[candidate];
556 UInt_t tmpTotalCharge=tmpCandidate->fTotalCharge;
559 fClusterMCVector.clear();
560 FillMCClusterVector(tmpPad->GetCandidateDigits(candidate));
563 ComparePads(fRowPadVector[row][pad+1],tmpCandidate,pad+1);
564 if(tmpCandidate->fTotalCharge>tmpTotalCharge){
566 fClusters.push_back(*tmpCandidate);
568 //sort the vector (large->small) according to weight and remove elements above 2 (keep 0 1 and 2)
569 sort(fClusterMCVector.begin(),fClusterMCVector.end(), MCWeight::CompareWeights );
570 ClusterMCInfo tmpClusterMCInfo;
576 if(fClusterMCVector.size()>0){
577 tmpClusterMCInfo.fClusterID[0]=fClusterMCVector.at(0);
580 tmpClusterMCInfo.fClusterID[0]=zeroMC;
583 if(fClusterMCVector.size()>1){
584 tmpClusterMCInfo.fClusterID[1]=fClusterMCVector.at(1);
587 tmpClusterMCInfo.fClusterID[1]=zeroMC;
590 if(fClusterMCVector.size()>2){
591 tmpClusterMCInfo.fClusterID[2]=fClusterMCVector.at(2);
594 tmpClusterMCInfo.fClusterID[2]=zeroMC;
597 fClustersMCInfo.push_back(tmpClusterMCInfo);
602 tmpPad->ClearCandidates();
604 fRowPadVector[row][fNumberOfPadsInRow[row]]->ClearCandidates();
607 HLTInfo("Found %d clusters.",fClusters.size());
609 //TODO: Change so it stores AliHLTTPCSpacePointData directly, instead of this copying
611 AliClusterData * clusterlist = new AliClusterData[fClusters.size()]; //Clusterlist
612 for(unsigned int i=0;i<fClusters.size();i++){
613 clusterlist[i].fTotalCharge = fClusters[i].fTotalCharge;
614 clusterlist[i].fPad = fClusters[i].fPad;
615 clusterlist[i].fPad2 = fClusters[i].fPad2;
616 clusterlist[i].fTime = fClusters[i].fTime;
617 clusterlist[i].fTime2 = fClusters[i].fTime2;
618 clusterlist[i].fMean = fClusters[i].fMean;
619 clusterlist[i].fFlags = fClusters[i].fFlags;
620 clusterlist[i].fChargeFalling = fClusters[i].fChargeFalling;
621 clusterlist[i].fLastCharge = fClusters[i].fLastCharge;
622 clusterlist[i].fLastMergedPad = fClusters[i].fLastMergedPad;
623 clusterlist[i].fRow = fClusters[i].fRowNumber;
624 clusterlist[i].fQMax = fClusters[i].fQMax;
627 WriteClusters(fClusters.size(),clusterlist);
628 delete [] clusterlist;
630 if( fReleaseMemory ) DeInitializePadArray();// call this when the -releaseMemory flag is set
634 Bool_t AliHLTTPCClusterFinder::UpdateCalibDB(){
637 AliTPCcalibDB::Instance()->Update();
639 //uptate the transform class
640 AliTPCTransform * tmp = AliTPCcalibDB::Instance()->GetTransform();
642 HLTError("AliHLTTPCClusterFinder::UpdateCAlibDB: Offline transform not in AliTPCcalibDB.");
645 fOfflineTransform = tmp;
649 //---------------------------------- Under this line the old sorted clusterfinder functions can be found --------------------------------
652 void AliHLTTPCClusterFinder::PrintClusters(){
653 // see header file for class documentation
655 for(size_t i=0;i<fClusters.size();i++){
656 HLTInfo("Cluster number: %d",i);
657 HLTInfo("Row: %d \t Pad: %d",fClusters[i].fRowNumber,fClusters[i].fPad/fClusters[i].fTotalCharge);
658 HLTInfo("Total Charge: %d",fClusters[i].fTotalCharge);
659 HLTInfo("fPad: %d",fClusters[i].fPad);
660 HLTInfo("PadError: %d",fClusters[i].fPad2);
661 HLTInfo("TimeMean: %d",fClusters[i].fTime/fClusters[i].fTotalCharge);
662 HLTInfo("TimeError: %d",fClusters[i].fTime2);
663 HLTInfo("EndOfCluster:");
667 void AliHLTTPCClusterFinder::FillMCClusterVector(vector<AliHLTTPCDigitData> digitData){
669 for(UInt_t d=0;d<digitData.size();d++){
670 Int_t nIDsInDigit = (digitData.at(d).fTrackID[0]>=0) + (digitData.at(d).fTrackID[1]>=0) + (digitData.at(d).fTrackID[2]>=0);
671 for(Int_t id=0; id<3; id++){
672 if(digitData.at(d).fTrackID[id]>=0){
673 Bool_t matchFound = kFALSE;
675 mc.fMCID = digitData.at(d).fTrackID[id];
676 mc.fWeight = ((Float_t)digitData.at(d).fCharge)/nIDsInDigit;
677 for(UInt_t i=0;i<fClusterMCVector.size();i++){
678 if(mc.fMCID == fClusterMCVector.at(i).fMCID){
679 fClusterMCVector.at(i).fWeight += mc.fWeight;
683 if(matchFound == kFALSE){
684 fClusterMCVector.push_back(mc);
692 void AliHLTTPCClusterFinder::Read(void* ptr,unsigned long size){
694 fPtr = (UChar_t*)ptr;
698 void AliHLTTPCClusterFinder::ProcessDigits(){
699 // see header file for class documentation
702 bool readValue = true;
705 UShort_t time=0,newTime=0;
706 UInt_t pad=0,newPad=0;
707 AliHLTTPCSignal_t charge=0;
711 // initialize block for reading packed data
712 iResult=fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice);
713 if (iResult<0) return;
715 readValue = fDigitReader->Next();
717 // Matthias 08.11.2006 the following return would cause termination without writing the
718 // ClusterData and thus would block the component. I just want to have the commented line
719 // here for information
720 //if (!readValue)return;
722 pad = fDigitReader->GetPad();
723 time = fDigitReader->GetTime();
724 fCurrentRow = fDigitReader->GetRow();
726 if ( fCurrentPatch >= 2 ) // Outer sector, patches 2, 3, 4, 5
727 rowOffset = AliHLTTPCTransform::GetFirstRow( 2 );
729 fCurrentRow += rowOffset;
731 UInt_t lastpad = 123456789;
732 const UInt_t kPadArraySize=5000;
733 const UInt_t kClusterListSize=10000;
734 AliClusterData *pad1[kPadArraySize]; //2 lists for internal memory=2pads
735 AliClusterData *pad2[kPadArraySize]; //2 lists for internal memory=2pads
736 AliClusterData clusterlist[kClusterListSize]; //Clusterlist
738 AliClusterData **currentPt; //List of pointers to the current pad
739 AliClusterData **previousPt; //List of pointers to the previous pad
742 UInt_t nprevious=0,ncurrent=0,ntotal=0;
744 /* quick implementation of baseline calculation and zero suppression
745 open a pad object for each pad and delete it after processing.
746 later a list of pad objects with base line history can be used
747 The whole thing only works if we really get unprocessed raw data, if
748 the data is already zero suppressed, there might be gaps in the time
751 Int_t gatingGridOffset=50;
753 gatingGridOffset=fFirstTimeBin;
755 AliHLTTPCPad baseline(gatingGridOffset, AliHLTTPCTransform::GetNTimeBins());
756 // just to make later conversion to a list of objects easier
757 AliHLTTPCPad* pCurrentPad=NULL;
759 if (fSignalThreshold>=0) {
760 pCurrentPad=&baseline;
761 baseline.SetThreshold(fSignalThreshold);
764 while ( readValue!=0 && iResult>=0){ // Reads through all digits in block
771 if(currentPt == pad2){
779 nprevious = ncurrent;
781 if(pad != lastpad+1){
782 //this happens if there is a pad with no signal.
783 nprevious = ncurrent = 0;
788 Bool_t newcluster = kTRUE;
789 UInt_t seqcharge=0,seqaverage=0,seqerror=0;
790 AliHLTTPCSignal_t lastcharge=0;
791 UInt_t bLastWasFalling=0;
796 redo: //This is a goto.
807 while(iResult>=0){ //Loop over time bins of current pad
808 // read all the values for one pad at once to calculate the base line
810 if (!pCurrentPad->IsStarted()) {
811 //HLTDebug("reading data for pad %d, padrow %d", fDigitReader->GetPad(), fDigitReader->GetRow()+rowOffset);
812 pCurrentPad->SetID(fDigitReader->GetRow()+rowOffset,fDigitReader->GetPad());
813 if ((pCurrentPad->StartEvent())>=0) {
815 if ((fDigitReader->GetRow()+rowOffset)!=pCurrentPad->GetRowNumber()) break;
816 if (fDigitReader->GetPad()!=pCurrentPad->GetPadNumber()) break;
817 pCurrentPad->SetRawData(fDigitReader->GetTime(), fDigitReader->GetSignal());
818 //HLTDebug("set raw data to pad: bin %d charge %d", fDigitReader->GetTime(), fDigitReader->GetSignal());
819 } while ((readValue = fDigitReader->Next())!=0);
821 pCurrentPad->CalculateBaseLine(AliHLTTPCTransform::GetNTimeBins()/2);
822 if (pCurrentPad->Next(kTRUE/*do zero suppression*/)==0) {
823 //HLTDebug("no data available after zero suppression");
824 pCurrentPad->StopEvent();
825 pCurrentPad->ResetHistory();
828 time=pCurrentPad->GetCurrentPosition();
829 if (time>pCurrentPad->GetSize()) {
830 HLTError("invalid time bin for pad");
836 Float_t occupancy=pCurrentPad->GetOccupancy();
837 //HLTDebug("pad %d occupancy level: %f", pCurrentPad->GetPadNumber(), occupancy);
838 if ( occupancy < fOccupancyLimit ) {
839 charge = pCurrentPad->GetCorrectedData();
842 //HLTDebug("ignoring pad %d with occupancy level %f", pCurrentPad->GetPadNumber(), occupancy);
845 charge = fDigitReader->GetSignal();
847 //HLTDebug("get next charge value: position %d charge %d", time, charge);
851 if (fDigitReader->GetRow() == 90){
852 ///// LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::Row","row90") << "PAD=" << fDigitReader->GetPad() << " TIME=" << fDigitReader->GetTime()
853 // << " SIGNAL=" << fDigitReader->GetSignal() << ENDLOG;
857 if(time >= AliHLTTPCTransform::GetNTimeBins()){
858 HLTWarning("Pad %d: Timebin (%d) out of range (%d)", pad, time, AliHLTTPCTransform::GetNTimeBins());
863 //Get the current ADC-value
866 //Check if the last pixel in the sequence is smaller than this
867 if(charge > lastcharge){
873 else bLastWasFalling = 1; //last pixel was larger than this
877 //Sum the total charge of this sequence
879 seqaverage += time*charge;
880 seqerror += time*time*charge;
884 if((pCurrentPad->Next(kTRUE/*do zero suppression*/))==0) {
885 pCurrentPad->StopEvent();
886 pCurrentPad->ResetHistory();
888 newPad = fDigitReader->GetPad();
889 newTime = fDigitReader->GetTime();
890 newRow = fDigitReader->GetRow() + rowOffset;
895 newPad=pCurrentPad->GetPadNumber();
896 newTime=pCurrentPad->GetCurrentPosition();
897 newRow=pCurrentPad->GetRowNumber();
899 readValue = fDigitReader->Next();
900 //Check where to stop:
901 if(!readValue) break; //No more value
903 newPad = fDigitReader->GetPad();
904 newTime = fDigitReader->GetTime();
905 newRow = fDigitReader->GetRow() + rowOffset;
908 if(newPad != pad)break; //new pad
909 if(newTime != time+1) break; //end of sequence
912 // pad = newpad; is equal
915 }//end loop over sequence
917 //HLTDebug("ended time bin sequence loop: seqcharge=%d readValue=%d", seqcharge, readValue);
918 //HLTDebug("pad=%d newpad=%d current row=%d newrow=%d", pad, newPad, fCurrentRow, newRow);
920 // with active zero suppression zero values are possible
924 //Calculate mean of sequence:
927 seqmean = seqaverage/seqcharge;
929 LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::ProcessRow","Data")
930 <<"Error in data given to the cluster finder"<<ENDLOG;
935 //Calculate mean in pad direction:
936 Int_t padmean = seqcharge*pad;
937 Int_t paderror = pad*padmean;
939 //Compare with results on previous pad:
940 for(UInt_t p=0; p<nprevious && p<kPadArraySize && ncurrent<kPadArraySize; p++){
942 //dont merge sequences on the same pad twice
943 if(previousPt[p]->fLastMergedPad==pad) continue;
945 Int_t difference = seqmean - previousPt[p]->fMean;
946 if(difference < -fMatch) break;
948 if(difference <= fMatch){ //There is a match here!!
949 AliClusterData *local = previousPt[p];
952 if(seqcharge > local->fLastCharge){
953 if(local->fChargeFalling){ //The previous pad was falling
954 break; //create a new cluster
957 else local->fChargeFalling = 1;
958 local->fLastCharge = seqcharge;
961 //Don't create a new cluster, because we found a match
964 //Update cluster on current pad with the matching one:
965 local->fTotalCharge += seqcharge;
966 local->fPad += padmean;
967 local->fPad2 += paderror;
968 local->fTime += seqaverage;
969 local->fTime2 += seqerror;
970 local->fMean = seqmean;
971 local->fFlags++; //means we have more than one pad
972 local->fLastMergedPad = pad;
974 currentPt[ncurrent] = local;
978 } //Checking for match at previous pad
979 } //Loop over results on previous pad.
981 if(newcluster && ncurrent<kPadArraySize){
982 //Start a new cluster. Add it to the clusterlist, and update
983 //the list of pointers to clusters in current pad.
984 //current pad will be previous pad on next pad.
986 //Add to the clusterlist:
987 AliClusterData *tmp = &clusterlist[ntotal];
988 tmp->fTotalCharge = seqcharge;
990 tmp->fPad2 = paderror;
991 tmp->fTime = seqaverage;
992 tmp->fTime2 = seqerror;
993 tmp->fMean = seqmean;
994 tmp->fFlags = 0; //flags for single pad clusters
995 tmp->fLastMergedPad = pad;
998 tmp->fChargeFalling = 0;
999 tmp->fLastCharge = seqcharge;
1002 //Update list of pointers to previous pad:
1003 currentPt[ncurrent] = &clusterlist[ntotal];
1009 if(newbin >= 0) goto redo;
1011 // to prevent endless loop
1012 if(time >= AliHLTTPCTransform::GetNTimeBins()){
1013 HLTWarning("Timebin (%d) out of range (%d)", time, AliHLTTPCTransform::GetNTimeBins());
1018 if(!readValue) break; //No more value
1020 if (ntotal>=kClusterListSize || ncurrent>=kPadArraySize) {
1021 HLTWarning("pad array size exceeded ntotal=%d ncurrent=%d, skip rest of the data", ntotal, ncurrent);
1025 if(fCurrentRow != newRow){
1026 WriteClusters(ntotal,clusterlist);
1028 lastpad = 123456789;
1036 fCurrentRow = newRow;
1042 } // END while(readValue)
1044 WriteClusters(ntotal,clusterlist);
1046 HLTInfo("ClusterFinder found %d clusters in slice %d patch %d", fNClusters, fCurrentSlice, fCurrentPatch);
1050 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliClusterData *list){
1051 // see header file for class documentation
1053 //write cluster to output pointer
1054 Int_t thisrow=-1,thissector=-1;
1055 UInt_t counter = fNClusters;
1057 for(int j=0; j<nclusters; j++)
1062 if(!list[j].fFlags){
1064 if(j+(Int_t)fClustersMCInfo.size()-nclusters >=0 && j+fClustersMCInfo.size()-nclusters < fClustersMCInfo.size()){
1065 fClustersMCInfo.erase(fClustersMCInfo.begin()+j+fClustersMCInfo.size()-nclusters); // remove the mc info for this cluster since it is not taken into account
1068 continue; //discard single pad clusters
1070 if(list[j].fTotalCharge < fThreshold){
1072 if(j+(Int_t)fClustersMCInfo.size()-nclusters >=0 && j+fClustersMCInfo.size()-nclusters < fClustersMCInfo.size()){
1073 fClustersMCInfo.erase(fClustersMCInfo.begin()+j+fClustersMCInfo.size()-nclusters); // remove the mc info for this cluster since it is not taken into account
1076 continue; //noise cluster
1079 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1080 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1081 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1082 Float_t ftime2=fZErr*fZErr; //fixed given error
1087 fCurrentRow=list[j].fRow;
1091 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1092 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1093 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1094 // Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1095 Float_t sy2=(Float_t)list[j].fPad2 * list[j].fTotalCharge - (Float_t)list[j].fPad * list[j].fPad;
1098 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1099 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1103 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1105 fpad2*=0.108; //constants are from offline studies
1109 } else fpad2=sy2; //take the width not the error
1111 // Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1112 Float_t sz2=(Float_t)list[j].fTime2*list[j].fTotalCharge - (Float_t)list[j].fTime*list[j].fTime;
1115 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1116 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1120 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1122 ftime2 *= 0.169; //constants are from offline studies
1126 } else ftime2=sz2; //take the width, not the error
1130 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1133 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1135 if(fOfflineTransform == NULL){
1136 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1138 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1139 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1140 if(fNClusters >= fMaxNClusters)
1142 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1143 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1147 fSpacePointData[counter].fX = xyz[0];
1148 // fSpacePointData[counter].fY = xyz[1];
1149 if(fCurrentSlice<18){
1150 fSpacePointData[counter].fY = xyz[1];
1153 fSpacePointData[counter].fY = -1*xyz[1];
1155 fSpacePointData[counter].fZ = xyz[2];
1158 Double_t x[3]={thisrow,fpad+.5,ftime};
1159 Int_t iSector[1]={thissector};
1160 fOfflineTransform->Transform(x,iSector,0,1);
1161 fSpacePointData[counter].fX = x[0];
1162 fSpacePointData[counter].fY = x[1];
1163 fSpacePointData[counter].fZ = x[2];
1168 fSpacePointData[counter].fX = fCurrentRow;
1169 fSpacePointData[counter].fY = fpad;
1170 fSpacePointData[counter].fZ = ftime;
1173 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1174 fSpacePointData[counter].fPadRow = fCurrentRow;
1175 fSpacePointData[counter].fSigmaY2 = fpad2;
1176 fSpacePointData[counter].fSigmaZ2 = ftime2;
1178 fSpacePointData[counter].fQMax = list[j].fQMax;
1180 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1181 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1183 Int_t patch=fCurrentPatch;
1184 if(patch==-1) patch=0; //never store negative patch number
1185 fSpacePointData[counter].fID = counter
1186 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1190 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1192 fSpacePointData[counter].fTrackID[0] = trackID[0];
1193 fSpacePointData[counter].fTrackID[1] = trackID[1];
1194 fSpacePointData[counter].fTrackID[2] = trackID[2];
1203 // STILL TO FIX ----------------------------------------------------------------------------
1206 void AliHLTTPCClusterFinder::GetTrackID(Int_t pad,Int_t time,Int_t *trackID){
1207 // see header file for class documentation
1210 AliHLTTPCDigitRowData *rowPt = (AliHLTTPCDigitRowData*)fDigitRowData;
1212 trackID[0]=trackID[1]=trackID[2]=-2;
1213 for(Int_t i=fFirstRow; i<=fLastRow; i++){
1214 if(rowPt->fRow < (UInt_t)fCurrentRow){
1215 AliHLTTPCMemHandler::UpdateRowPointer(rowPt);
1218 AliHLTTPCDigitData *digPt = (AliHLTTPCDigitData*)rowPt->fDigitData;
1219 for(UInt_t j=0; j<rowPt->fNDigit; j++){
1220 Int_t cpad = digPt[j].fPad;
1221 Int_t ctime = digPt[j].fTime;
1222 if(cpad != pad) continue;
1223 if(ctime != time) continue;
1225 trackID[0] = digPt[j].fTrackID[0];
1226 trackID[1] = digPt[j].fTrackID[1];
1227 trackID[2] = digPt[j].fTrackID[2];
1238 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliHLTTPCClusters *list){//This is used when using the AliHLTTPCClusters class for cluster data
1239 // see header file for class documentation
1241 //write cluster to output pointer
1242 Int_t thisrow,thissector;
1243 UInt_t counter = fNClusters;
1245 for(int j=0; j<nclusters; j++)
1247 if(!list[j].fFlags) continue; //discard single pad clusters
1248 if(list[j].fTotalCharge < fThreshold) continue; //noise cluster
1251 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1252 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1253 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1254 Float_t ftime2=fZErr*fZErr; //fixed given error
1257 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1258 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1259 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1260 Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1263 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1264 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1268 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1270 fpad2*=0.108; //constants are from offline studies
1274 } else fpad2=sy2; //take the width not the error
1276 Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1279 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1280 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1284 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1286 ftime2 *= 0.169; //constants are from offline studies
1290 } else ftime2=sz2; //take the width, not the error
1294 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1297 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1298 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1300 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1301 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1302 if(fNClusters >= fMaxNClusters)
1304 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1305 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1309 fSpacePointData[counter].fX = xyz[0];
1310 // fSpacePointData[counter].fY = xyz[1];
1311 if(fCurrentSlice<18){
1312 fSpacePointData[counter].fY = xyz[1];
1315 fSpacePointData[counter].fY = -1*xyz[1];
1317 fSpacePointData[counter].fZ = xyz[2];
1320 fSpacePointData[counter].fX = fCurrentRow;
1321 fSpacePointData[counter].fY = fpad;
1322 fSpacePointData[counter].fZ = ftime;
1325 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1326 fSpacePointData[counter].fPadRow = fCurrentRow;
1327 fSpacePointData[counter].fSigmaY2 = fpad2;
1328 fSpacePointData[counter].fSigmaZ2 = ftime2;
1330 fSpacePointData[counter].fQMax = list[j].fQMax;
1332 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1333 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1335 Int_t patch=fCurrentPatch;
1336 if(patch==-1) patch=0; //never store negative patch number
1337 fSpacePointData[counter].fID = counter
1338 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1342 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1344 fSpacePointData[counter].fTrackID[0] = trackID[0];
1345 fSpacePointData[counter].fTrackID[1] = trackID[1];
1346 fSpacePointData[counter].fTrackID[2] = trackID[2];