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"
42 ClassImp(AliHLTTPCClusterFinder)
44 AliHLTTPCClusterFinder::AliHLTTPCClusterFinder()
46 fClustersHWAddressVector(),
48 fSpacePointData(NULL),
70 fVectorInitialized(kFALSE),
74 fNumberOfPadsInRow(NULL),
76 fRowOfFirstCandidate(0),
77 fDoPadSelection(kFALSE),
79 fLastTimeBin(AliHLTTPCTransform::GetNTimeBins()),
80 fTotalChargeOfPreviousClusterCandidate(0),
81 fChargeOfCandidatesFalling(kFALSE),
89 AliHLTTPCClusterFinder::~AliHLTTPCClusterFinder(){
90 // see header file for class documentation
93 if(fVectorInitialized){
94 DeInitializePadArray();
96 if(fNumberOfPadsInRow){
97 delete [] fNumberOfPadsInRow;
98 fNumberOfPadsInRow=NULL;
102 void AliHLTTPCClusterFinder::InitSlice(Int_t slice,Int_t patch,Int_t nmaxpoints){
103 // see header file for class documentation
107 fMaxNClusters = nmaxpoints;
108 fCurrentSlice = slice;
109 fCurrentPatch = patch;
110 fFirstRow=AliHLTTPCTransform::GetFirstRow(patch);
111 fLastRow=AliHLTTPCTransform::GetLastRow(patch);
114 fClustersMCInfo.clear();
116 fClusterMCVector.clear();
119 void AliHLTTPCClusterFinder::InitializePadArray(){
120 // see header file for class documentation
122 if(fCurrentPatch>5||fCurrentPatch<0){
123 HLTFatal("Patch is not set");
127 HLTDebug("Patch number=%d",fCurrentPatch);
129 fFirstRow = AliHLTTPCTransform::GetFirstRow(fCurrentPatch);
130 fLastRow = AliHLTTPCTransform::GetLastRow(fCurrentPatch);
132 fNumberOfRows=fLastRow-fFirstRow+1;
133 fNumberOfPadsInRow= new UInt_t[fNumberOfRows];
135 memset( fNumberOfPadsInRow, 0, sizeof(Int_t)*(fNumberOfRows));
137 for(UInt_t i=0;i<fNumberOfRows;i++){
138 fNumberOfPadsInRow[i]=AliHLTTPCTransform::GetNPads(i+fFirstRow);
139 AliHLTTPCPadVector tmpRow;
140 for(UInt_t j=0;j<=fNumberOfPadsInRow[i];j++){
141 AliHLTTPCPad *tmpPad = new AliHLTTPCPad(2);
143 tmpRow.push_back(tmpPad);
145 fRowPadVector.push_back(tmpRow);
147 fVectorInitialized=kTRUE;
150 Int_t AliHLTTPCClusterFinder::DeInitializePadArray(){
151 // see header file for class documentation
153 for(UInt_t i=0;i<fNumberOfRows;i++){
154 for(UInt_t j=0;j<=fNumberOfPadsInRow[i];j++){
155 delete fRowPadVector[i][j];
156 fRowPadVector[i][j]=NULL;
158 fRowPadVector[i].clear();
160 fRowPadVector.clear();
166 void AliHLTTPCClusterFinder::SetOutputArray(AliHLTTPCSpacePointData *pt){
167 // see header file for class documentation
168 //set pointer to output
169 fSpacePointData = pt;
173 void AliHLTTPCClusterFinder::ReadDataUnsorted(void* ptr,unsigned long size){
174 // see header file for class documentation
176 fPtr = (UChar_t*)ptr;
179 if(!fVectorInitialized){
180 InitializePadArray();
183 if (fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice)<0) {
184 HLTError("failed setting up digit reader (InitBlock)");
188 while(fDigitReader->NextChannel()){
189 UInt_t row=fDigitReader->GetRow();
190 UInt_t pad=fDigitReader->GetPad();
192 if(row>=fRowPadVector.size()){
193 HLTError("Row number is to large: %d, max is %d",row,fRowPadVector.size()-1);
196 if(pad>=fRowPadVector[row].size()){
197 HLTError("Pad number is to large: %d, max is %d",pad,fRowPadVector[row].size());
201 while(fDigitReader->NextBunch()){
202 if(fDigitReader->GetBunchSize()>1){//to remove single timebin values, this will have to change at some point
203 UInt_t time = fDigitReader->GetTime();
204 if((Int_t)time>=fFirstTimeBin && (Int_t)time+fDigitReader->GetBunchSize()<=fLastTimeBin){
205 // Kenneth: 20-04-09. The following if have been added because of inconsistency in the 40 bit decoder and the 32 bit decoder.
206 // GetSignals() in the 40 bit decoder returns an array of UInt_t while the 32 bit one returns UShort_t
207 // The same is true for the function ReadDataUnsortedDeconvoluteTime() below.
208 // In addition the signals are organized in the opposite direction
210 const UShort_t *bunchData= fDigitReader->GetSignalsShort();
211 AliHLTTPCClusters candidate;
212 for(Int_t i=fDigitReader->GetBunchSize()-1;i>=0;i--){
213 candidate.fTotalCharge+=bunchData[i];
214 candidate.fTime += time*bunchData[i];
215 candidate.fTime2 += time*time*bunchData[i];
216 if(bunchData[i]>candidate.fQMax){
217 candidate.fQMax=bunchData[i];
221 if(candidate.fTotalCharge>0){
222 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
223 candidate.fPad=candidate.fTotalCharge*pad;
224 candidate.fPad2=candidate.fPad*pad;
225 candidate.fLastMergedPad=pad;
226 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
228 if(fRowPadVector[row][pad] != NULL){
229 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
233 const UInt_t *bunchData= fDigitReader->GetSignals();
234 AliHLTTPCClusters candidate;
235 const AliHLTTPCDigitData* digits = NULL;
236 if(fDoMC && (digits = fDigitReader->GetBunchDigits())!=NULL){
237 for(Int_t i=0;i<fDigitReader->GetBunchSize();i++){
238 candidate.fTotalCharge+=bunchData[i];
239 candidate.fTime += time*bunchData[i];
240 candidate.fTime2 += time*time*bunchData[i];
241 if(bunchData[i]>candidate.fQMax){
242 candidate.fQMax=bunchData[i];
244 fMCDigits.push_back(digits[i]);
249 for(Int_t i=0;i<fDigitReader->GetBunchSize();i++){
250 candidate.fTotalCharge+=bunchData[i];
251 candidate.fTime += time*bunchData[i];
252 candidate.fTime2 += time*time*bunchData[i];
253 if(bunchData[i]>candidate.fQMax){
254 candidate.fQMax=bunchData[i];
259 if(candidate.fTotalCharge>0){
260 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
261 candidate.fPad=candidate.fTotalCharge*pad;
262 candidate.fPad2=candidate.fPad*pad;
263 candidate.fLastMergedPad=pad;
264 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
266 if(fRowPadVector[row][pad] != NULL){
267 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
269 fRowPadVector[row][pad]->AddCandidateDigits(fMCDigits);
280 void AliHLTTPCClusterFinder::ReadDataUnsortedDeconvoluteTime(void* ptr,unsigned long size){
281 // see header file for class documentation
284 fPtr = (UChar_t*)ptr;
287 if(!fVectorInitialized){
288 InitializePadArray();
291 if (fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice)<0) {
292 HLTError("failed setting up digit reader (InitBlock)");
296 while(fDigitReader->NextChannel()){
297 UInt_t row=fDigitReader->GetRow();
298 UInt_t pad=fDigitReader->GetPad();
300 while(fDigitReader->NextBunch()){
301 if(fDigitReader->GetBunchSize()>1){//to remove single timebin values, this will have to change at some point
302 UInt_t time = fDigitReader->GetTime();
303 if((Int_t)time>=fFirstTimeBin && (Int_t)time+fDigitReader->GetBunchSize()<=fLastTimeBin){
304 Int_t indexInBunchData=0;
305 Bool_t moreDataInBunch=kFALSE;
307 Bool_t signalFalling=kFALSE;
309 // Kenneth: 20-04-09. The following if have been added because of inconsistency in the 40 bit decoder and the 32 bit decoder.
310 // GetSignals() in the 40 bit decoder returns an array of UInt_t while the 32 bit one returns UShort_t
311 // The same is true for the function ReadDataUnsorted() above.
312 // In addition the signals are organized in the opposite direction
314 indexInBunchData = fDigitReader->GetBunchSize();
315 const UShort_t *bunchData= fDigitReader->GetSignalsShort();
317 AliHLTTPCClusters candidate;
318 //for(Int_t i=indexInBunchData;i<fDigitReader->GetBunchSize();i++){
319 for(Int_t i=indexInBunchData;i>=0;i--){
320 // Checks if one need to deconvolute the signals
321 if(bunchData[i]>prevSignal && signalFalling==kTRUE){
322 if(i<fDigitReader->GetBunchSize()-1){ // means there are more than one signal left in the bunch
323 moreDataInBunch=kTRUE;
329 // Checks if the signal is 0, then quit processing the data.
330 if(bunchData[i]==0 && i<fDigitReader->GetBunchSize()-1){//means we have 0 data fom the rcu, might happen depending on the configuration settings
331 moreDataInBunch=kTRUE;
336 if(prevSignal>bunchData[i]){//means the peak of the signal has been reached and deconvolution will happen if the signal rise again.
339 candidate.fTotalCharge+=bunchData[i];
340 candidate.fTime += time*bunchData[i];
341 candidate.fTime2 += time*time*bunchData[i];
342 if(bunchData[i]>candidate.fQMax){
343 candidate.fQMax=bunchData[i];
346 prevSignal=bunchData[i];
350 if(candidate.fTotalCharge>0){
351 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
352 candidate.fPad=candidate.fTotalCharge*pad;
353 candidate.fPad2=candidate.fPad*pad;
354 candidate.fLastMergedPad=pad;
355 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
357 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
358 fRowPadVector[row][pad]->AddCandidateDigits(fMCDigits);
359 if(indexInBunchData<fDigitReader->GetBunchSize()-1){
360 moreDataInBunch=kFALSE;
362 }while(moreDataInBunch);
365 const UInt_t *bunchData= fDigitReader->GetSignals();
367 AliHLTTPCClusters candidate;
368 for(Int_t i=indexInBunchData;i<fDigitReader->GetBunchSize();i++){
369 // Checks if one need to deconvolute the signals
370 if(bunchData[i]>prevSignal && signalFalling==kTRUE){
371 if(i<fDigitReader->GetBunchSize()-1){ // means there are more than one signal left in the bunch
372 moreDataInBunch=kTRUE;
378 // Checks if the signal is 0, then quit processing the data.
379 if(bunchData[i]==0 && i<fDigitReader->GetBunchSize()-1){//means we have 0 data fom the rcu, might happen depending on the configuration settings
380 moreDataInBunch=kTRUE;
385 if(prevSignal>bunchData[i]){//means the peak of the signal has been reached and deconvolution will happen if the signal rise again.
388 candidate.fTotalCharge+=bunchData[i];
389 candidate.fTime += time*bunchData[i];
390 candidate.fTime2 += time*time*bunchData[i];
391 if(bunchData[i]>candidate.fQMax){
392 candidate.fQMax=bunchData[i];
395 prevSignal=bunchData[i];
399 if(candidate.fTotalCharge>0){
400 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
401 candidate.fPad=candidate.fTotalCharge*pad;
402 candidate.fPad2=candidate.fPad*pad;
403 candidate.fLastMergedPad=pad;
404 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
406 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
407 if(indexInBunchData<fDigitReader->GetBunchSize()-1){
408 moreDataInBunch=kFALSE;
410 }while(moreDataInBunch);
418 Bool_t AliHLTTPCClusterFinder::ComparePads(AliHLTTPCPad *nextPad,AliHLTTPCClusters* cluster,Int_t nextPadToRead){
419 // see header file for class documentation
421 //Checking if we have a match on the next pad
422 for(UInt_t candidateNumber=0;candidateNumber<nextPad->fClusterCandidates.size();candidateNumber++){
423 AliHLTTPCClusters *candidate =&nextPad->fClusterCandidates[candidateNumber];
424 if(cluster->fMean-candidate->fMean==1 || candidate->fMean-cluster->fMean==1 || cluster->fMean-candidate->fMean==0){
426 if(candidate->fTotalCharge<fTotalChargeOfPreviousClusterCandidate){//peak is reached
427 fChargeOfCandidatesFalling=kTRUE;
429 if(candidate->fTotalCharge>fTotalChargeOfPreviousClusterCandidate && fChargeOfCandidatesFalling==kTRUE){//we have deconvolution
433 cluster->fMean=candidate->fMean;
434 cluster->fTotalCharge+=candidate->fTotalCharge;
435 cluster->fTime += candidate->fTime;
436 cluster->fTime2 += candidate->fTime2;
437 cluster->fPad+=candidate->fPad;
438 cluster->fPad2+=candidate->fPad2;
439 cluster->fLastMergedPad=candidate->fPad;
440 if(candidate->fQMax>cluster->fQMax){
441 cluster->fQMax=candidate->fQMax;
444 FillMCClusterVector(nextPad->GetCandidateDigits(candidateNumber));
448 UInt_t rowNo = nextPad->GetRowNumber();
449 UInt_t padNo = nextPad->GetPadNumber();
451 fRowPadVector[rowNo][padNo-2]->fSelectedPad=kTRUE;
452 fRowPadVector[rowNo][padNo-2]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo-2);
454 fRowPadVector[rowNo][padNo-1]->fSelectedPad=kTRUE;// quick solution to set the first pad to selected
455 fRowPadVector[rowNo][padNo-1]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo-1);
456 fRowPadVector[rowNo][padNo]->fSelectedPad=kTRUE;
457 fRowPadVector[rowNo][padNo]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo);
460 //setting the matched pad to used
461 nextPad->fUsedClusterCandidates[candidateNumber]=1;
463 if(nextPadToRead<(Int_t)fNumberOfPadsInRow[fRowOfFirstCandidate]){
464 nextPad=fRowPadVector[fRowOfFirstCandidate][nextPadToRead];
465 ComparePads(nextPad,cluster,nextPadToRead);
478 Int_t AliHLTTPCClusterFinder::FillHWAddressList(AliHLTUInt16_t *hwaddlist, Int_t maxHWadd){
479 // see header file for class documentation
482 for(UInt_t row=0;row<fNumberOfRows;row++){
483 for(UInt_t pad=0;pad<fNumberOfPadsInRow[row]-1;pad++){
484 if(fRowPadVector[row][pad]->fSelectedPad){
485 if(counter<maxHWadd){
486 hwaddlist[counter]=(AliHLTUInt16_t)fRowPadVector[row][pad]->fHWAddress;
490 HLTWarning("To many hardwareaddresses, skip adding");
500 Int_t AliHLTTPCClusterFinder::FillOutputMCInfo(AliHLTTPCClusterFinder::ClusterMCInfo * outputMCInfo, Int_t maxNumberOfClusterMCInfo){
501 // see header file for class documentation
505 for(UInt_t mc=0;mc<fClustersMCInfo.size();mc++){
506 if(counter<maxNumberOfClusterMCInfo){
507 outputMCInfo[counter] = fClustersMCInfo[mc];
511 HLTWarning("To much MCInfo has been added (no more space), skip adding");
517 void AliHLTTPCClusterFinder::FindClusters(){
518 // see header file for function documentation
520 AliHLTTPCClusters* tmpCandidate=NULL;
521 for(UInt_t row=0;row<fNumberOfRows;row++){
522 fRowOfFirstCandidate=row;
523 for(UInt_t pad=0;pad<fNumberOfPadsInRow[row];pad++){
524 AliHLTTPCPad *tmpPad=fRowPadVector[row][pad];
525 for(size_t candidate=0;candidate<tmpPad->fClusterCandidates.size();candidate++){
526 if(tmpPad->fUsedClusterCandidates[candidate]){
529 tmpCandidate=&tmpPad->fClusterCandidates[candidate];
530 UInt_t tmpTotalCharge=tmpCandidate->fTotalCharge;
533 fClusterMCVector.clear();
534 FillMCClusterVector(tmpPad->GetCandidateDigits(candidate));
537 ComparePads(fRowPadVector[row][pad+1],tmpCandidate,pad+1);
538 if(tmpCandidate->fTotalCharge>tmpTotalCharge){
540 fClusters.push_back(*tmpCandidate);
542 //sort the vector (large->small) according to weight and remove elements above 2 (keep 0 1 and 2)
543 sort(fClusterMCVector.begin(),fClusterMCVector.end(), MCWeight::CompareWeights );
544 ClusterMCInfo tmpClusterMCInfo;
550 if(fClusterMCVector.size()>0){
551 tmpClusterMCInfo.fClusterID[0]=fClusterMCVector.at(0);
554 tmpClusterMCInfo.fClusterID[0]=zeroMC;
557 if(fClusterMCVector.size()>1){
558 tmpClusterMCInfo.fClusterID[1]=fClusterMCVector.at(1);
561 tmpClusterMCInfo.fClusterID[1]=zeroMC;
564 if(fClusterMCVector.size()>2){
565 tmpClusterMCInfo.fClusterID[2]=fClusterMCVector.at(2);
568 tmpClusterMCInfo.fClusterID[2]=zeroMC;
571 fClustersMCInfo.push_back(tmpClusterMCInfo);
576 tmpPad->ClearCandidates();
578 fRowPadVector[row][fNumberOfPadsInRow[row]]->ClearCandidates();
581 HLTInfo("Found %d clusters.",fClusters.size());
583 //TODO: Change so it stores AliHLTTPCSpacePointData directly, instead of this copying
585 AliClusterData * clusterlist = new AliClusterData[fClusters.size()]; //Clusterlist
586 for(unsigned int i=0;i<fClusters.size();i++){
587 clusterlist[i].fTotalCharge = fClusters[i].fTotalCharge;
588 clusterlist[i].fPad = fClusters[i].fPad;
589 clusterlist[i].fPad2 = fClusters[i].fPad2;
590 clusterlist[i].fTime = fClusters[i].fTime;
591 clusterlist[i].fTime2 = fClusters[i].fTime2;
592 clusterlist[i].fMean = fClusters[i].fMean;
593 clusterlist[i].fFlags = fClusters[i].fFlags;
594 clusterlist[i].fChargeFalling = fClusters[i].fChargeFalling;
595 clusterlist[i].fLastCharge = fClusters[i].fLastCharge;
596 clusterlist[i].fLastMergedPad = fClusters[i].fLastMergedPad;
597 clusterlist[i].fRow = fClusters[i].fRowNumber;
598 clusterlist[i].fQMax = fClusters[i].fQMax;
601 WriteClusters(fClusters.size(),clusterlist);
602 delete [] clusterlist;
607 //---------------------------------- Under this line the old sorted clusterfinder functions can be found --------------------------------
610 void AliHLTTPCClusterFinder::PrintClusters(){
611 // see header file for class documentation
613 for(size_t i=0;i<fClusters.size();i++){
614 HLTInfo("Cluster number: %d",i);
615 HLTInfo("Row: %d \t Pad: %d",fClusters[i].fRowNumber,fClusters[i].fPad/fClusters[i].fTotalCharge);
616 HLTInfo("Total Charge: %d",fClusters[i].fTotalCharge);
617 HLTInfo("fPad: %d",fClusters[i].fPad);
618 HLTInfo("PadError: %d",fClusters[i].fPad2);
619 HLTInfo("TimeMean: %d",fClusters[i].fTime/fClusters[i].fTotalCharge);
620 HLTInfo("TimeError: %d",fClusters[i].fTime2);
621 HLTInfo("EndOfCluster:");
625 void AliHLTTPCClusterFinder::FillMCClusterVector(vector<AliHLTTPCDigitData> digitData){
627 for(UInt_t d=0;d<digitData.size();d++){
628 Int_t nIDsInDigit = (digitData.at(d).fTrackID[0]>=0) + (digitData.at(d).fTrackID[1]>=0) + (digitData.at(d).fTrackID[2]>=0);
629 for(Int_t id=0; id<3; id++){
630 if(digitData.at(d).fTrackID[id]>=0){
631 Bool_t matchFound = kFALSE;
633 mc.fMCID = digitData.at(d).fTrackID[id];
634 mc.fWeight = ((Float_t)digitData.at(d).fCharge)/nIDsInDigit;
635 for(UInt_t i=0;i<fClusterMCVector.size();i++){
636 if(mc.fMCID == fClusterMCVector.at(i).fMCID){
637 fClusterMCVector.at(i).fWeight += mc.fWeight;
641 if(matchFound == kFALSE){
642 fClusterMCVector.push_back(mc);
650 void AliHLTTPCClusterFinder::Read(void* ptr,unsigned long size){
652 fPtr = (UChar_t*)ptr;
656 void AliHLTTPCClusterFinder::ProcessDigits(){
657 // see header file for class documentation
660 bool readValue = true;
663 UShort_t time=0,newTime=0;
664 UInt_t pad=0,newPad=0;
665 AliHLTTPCSignal_t charge=0;
669 // initialize block for reading packed data
670 iResult=fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice);
671 if (iResult<0) return;
673 readValue = fDigitReader->Next();
675 // Matthias 08.11.2006 the following return would cause termination without writing the
676 // ClusterData and thus would block the component. I just want to have the commented line
677 // here for information
678 //if (!readValue)return;
680 pad = fDigitReader->GetPad();
681 time = fDigitReader->GetTime();
682 fCurrentRow = fDigitReader->GetRow();
684 if ( fCurrentPatch >= 2 ) // Outer sector, patches 2, 3, 4, 5
685 rowOffset = AliHLTTPCTransform::GetFirstRow( 2 );
687 fCurrentRow += rowOffset;
689 UInt_t lastpad = 123456789;
690 const UInt_t kPadArraySize=5000;
691 const UInt_t kClusterListSize=10000;
692 AliClusterData *pad1[kPadArraySize]; //2 lists for internal memory=2pads
693 AliClusterData *pad2[kPadArraySize]; //2 lists for internal memory=2pads
694 AliClusterData clusterlist[kClusterListSize]; //Clusterlist
696 AliClusterData **currentPt; //List of pointers to the current pad
697 AliClusterData **previousPt; //List of pointers to the previous pad
700 UInt_t nprevious=0,ncurrent=0,ntotal=0;
702 /* quick implementation of baseline calculation and zero suppression
703 open a pad object for each pad and delete it after processing.
704 later a list of pad objects with base line history can be used
705 The whole thing only works if we really get unprocessed raw data, if
706 the data is already zero suppressed, there might be gaps in the time
709 Int_t gatingGridOffset=50;
711 gatingGridOffset=fFirstTimeBin;
713 AliHLTTPCPad baseline(gatingGridOffset, AliHLTTPCTransform::GetNTimeBins());
714 // just to make later conversion to a list of objects easier
715 AliHLTTPCPad* pCurrentPad=NULL;
717 if (fSignalThreshold>=0) {
718 pCurrentPad=&baseline;
719 baseline.SetThreshold(fSignalThreshold);
722 while ( readValue!=0 && iResult>=0){ // Reads through all digits in block
729 if(currentPt == pad2){
737 nprevious = ncurrent;
739 if(pad != lastpad+1){
740 //this happens if there is a pad with no signal.
741 nprevious = ncurrent = 0;
746 Bool_t newcluster = kTRUE;
747 UInt_t seqcharge=0,seqaverage=0,seqerror=0;
748 AliHLTTPCSignal_t lastcharge=0;
749 UInt_t bLastWasFalling=0;
754 redo: //This is a goto.
765 while(iResult>=0){ //Loop over time bins of current pad
766 // read all the values for one pad at once to calculate the base line
768 if (!pCurrentPad->IsStarted()) {
769 //HLTDebug("reading data for pad %d, padrow %d", fDigitReader->GetPad(), fDigitReader->GetRow()+rowOffset);
770 pCurrentPad->SetID(fDigitReader->GetRow()+rowOffset,fDigitReader->GetPad());
771 if ((pCurrentPad->StartEvent())>=0) {
773 if ((fDigitReader->GetRow()+rowOffset)!=pCurrentPad->GetRowNumber()) break;
774 if (fDigitReader->GetPad()!=pCurrentPad->GetPadNumber()) break;
775 pCurrentPad->SetRawData(fDigitReader->GetTime(), fDigitReader->GetSignal());
776 //HLTDebug("set raw data to pad: bin %d charge %d", fDigitReader->GetTime(), fDigitReader->GetSignal());
777 } while ((readValue = fDigitReader->Next())!=0);
779 pCurrentPad->CalculateBaseLine(AliHLTTPCTransform::GetNTimeBins()/2);
780 if (pCurrentPad->Next(kTRUE/*do zero suppression*/)==0) {
781 //HLTDebug("no data available after zero suppression");
782 pCurrentPad->StopEvent();
783 pCurrentPad->ResetHistory();
786 time=pCurrentPad->GetCurrentPosition();
787 if (time>pCurrentPad->GetSize()) {
788 HLTError("invalid time bin for pad");
794 Float_t occupancy=pCurrentPad->GetOccupancy();
795 //HLTDebug("pad %d occupancy level: %f", pCurrentPad->GetPadNumber(), occupancy);
796 if ( occupancy < fOccupancyLimit ) {
797 charge = pCurrentPad->GetCorrectedData();
800 //HLTDebug("ignoring pad %d with occupancy level %f", pCurrentPad->GetPadNumber(), occupancy);
803 charge = fDigitReader->GetSignal();
805 //HLTDebug("get next charge value: position %d charge %d", time, charge);
809 if (fDigitReader->GetRow() == 90){
810 ///// LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::Row","row90") << "PAD=" << fDigitReader->GetPad() << " TIME=" << fDigitReader->GetTime()
811 // << " SIGNAL=" << fDigitReader->GetSignal() << ENDLOG;
815 if(time >= AliHLTTPCTransform::GetNTimeBins()){
816 HLTWarning("Pad %d: Timebin (%d) out of range (%d)", pad, time, AliHLTTPCTransform::GetNTimeBins());
821 //Get the current ADC-value
824 //Check if the last pixel in the sequence is smaller than this
825 if(charge > lastcharge){
831 else bLastWasFalling = 1; //last pixel was larger than this
835 //Sum the total charge of this sequence
837 seqaverage += time*charge;
838 seqerror += time*time*charge;
842 if((pCurrentPad->Next(kTRUE/*do zero suppression*/))==0) {
843 pCurrentPad->StopEvent();
844 pCurrentPad->ResetHistory();
846 newPad = fDigitReader->GetPad();
847 newTime = fDigitReader->GetTime();
848 newRow = fDigitReader->GetRow() + rowOffset;
853 newPad=pCurrentPad->GetPadNumber();
854 newTime=pCurrentPad->GetCurrentPosition();
855 newRow=pCurrentPad->GetRowNumber();
857 readValue = fDigitReader->Next();
858 //Check where to stop:
859 if(!readValue) break; //No more value
861 newPad = fDigitReader->GetPad();
862 newTime = fDigitReader->GetTime();
863 newRow = fDigitReader->GetRow() + rowOffset;
866 if(newPad != pad)break; //new pad
867 if(newTime != time+1) break; //end of sequence
870 // pad = newpad; is equal
873 }//end loop over sequence
875 //HLTDebug("ended time bin sequence loop: seqcharge=%d readValue=%d", seqcharge, readValue);
876 //HLTDebug("pad=%d newpad=%d current row=%d newrow=%d", pad, newPad, fCurrentRow, newRow);
878 // with active zero suppression zero values are possible
882 //Calculate mean of sequence:
885 seqmean = seqaverage/seqcharge;
887 LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::ProcessRow","Data")
888 <<"Error in data given to the cluster finder"<<ENDLOG;
893 //Calculate mean in pad direction:
894 Int_t padmean = seqcharge*pad;
895 Int_t paderror = pad*padmean;
897 //Compare with results on previous pad:
898 for(UInt_t p=0; p<nprevious && p<kPadArraySize && ncurrent<kPadArraySize; p++){
900 //dont merge sequences on the same pad twice
901 if(previousPt[p]->fLastMergedPad==pad) continue;
903 Int_t difference = seqmean - previousPt[p]->fMean;
904 if(difference < -fMatch) break;
906 if(difference <= fMatch){ //There is a match here!!
907 AliClusterData *local = previousPt[p];
910 if(seqcharge > local->fLastCharge){
911 if(local->fChargeFalling){ //The previous pad was falling
912 break; //create a new cluster
915 else local->fChargeFalling = 1;
916 local->fLastCharge = seqcharge;
919 //Don't create a new cluster, because we found a match
922 //Update cluster on current pad with the matching one:
923 local->fTotalCharge += seqcharge;
924 local->fPad += padmean;
925 local->fPad2 += paderror;
926 local->fTime += seqaverage;
927 local->fTime2 += seqerror;
928 local->fMean = seqmean;
929 local->fFlags++; //means we have more than one pad
930 local->fLastMergedPad = pad;
932 currentPt[ncurrent] = local;
936 } //Checking for match at previous pad
937 } //Loop over results on previous pad.
939 if(newcluster && ncurrent<kPadArraySize){
940 //Start a new cluster. Add it to the clusterlist, and update
941 //the list of pointers to clusters in current pad.
942 //current pad will be previous pad on next pad.
944 //Add to the clusterlist:
945 AliClusterData *tmp = &clusterlist[ntotal];
946 tmp->fTotalCharge = seqcharge;
948 tmp->fPad2 = paderror;
949 tmp->fTime = seqaverage;
950 tmp->fTime2 = seqerror;
951 tmp->fMean = seqmean;
952 tmp->fFlags = 0; //flags for single pad clusters
953 tmp->fLastMergedPad = pad;
956 tmp->fChargeFalling = 0;
957 tmp->fLastCharge = seqcharge;
960 //Update list of pointers to previous pad:
961 currentPt[ncurrent] = &clusterlist[ntotal];
967 if(newbin >= 0) goto redo;
969 // to prevent endless loop
970 if(time >= AliHLTTPCTransform::GetNTimeBins()){
971 HLTWarning("Timebin (%d) out of range (%d)", time, AliHLTTPCTransform::GetNTimeBins());
976 if(!readValue) break; //No more value
978 if (ntotal>=kClusterListSize || ncurrent>=kPadArraySize) {
979 HLTWarning("pad array size exceeded ntotal=%d ncurrent=%d, skip rest of the data", ntotal, ncurrent);
983 if(fCurrentRow != newRow){
984 WriteClusters(ntotal,clusterlist);
994 fCurrentRow = newRow;
1000 } // END while(readValue)
1002 WriteClusters(ntotal,clusterlist);
1004 HLTInfo("ClusterFinder found %d clusters in slice %d patch %d", fNClusters, fCurrentSlice, fCurrentPatch);
1008 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliClusterData *list){
1009 // see header file for class documentation
1011 //write cluster to output pointer
1012 Int_t thisrow=-1,thissector=-1;
1013 UInt_t counter = fNClusters;
1015 for(int j=0; j<nclusters; j++)
1020 if(!list[j].fFlags){
1022 fClustersMCInfo.erase(fClustersMCInfo.begin()+j); // remove the mc ifo for this cluster since it is not taken into account
1024 continue; //discard single pad clusters
1026 if(list[j].fTotalCharge < fThreshold){
1028 fClustersMCInfo.erase(fClustersMCInfo.begin()+j); // remove the mc ifo for this cluster since it is not taken into account
1030 continue; //noise cluster
1033 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1034 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1035 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1036 Float_t ftime2=fZErr*fZErr; //fixed given error
1041 fCurrentRow=list[j].fRow;
1045 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1046 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1047 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1048 // Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1049 Float_t sy2=(Float_t)list[j].fPad2 * list[j].fTotalCharge - (Float_t)list[j].fPad * list[j].fPad;
1052 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1053 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1057 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1059 fpad2*=0.108; //constants are from offline studies
1063 } else fpad2=sy2; //take the width not the error
1065 // Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1066 Float_t sz2=(Float_t)list[j].fTime2*list[j].fTotalCharge - (Float_t)list[j].fTime*list[j].fTime;
1069 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1070 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1074 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1076 ftime2 *= 0.169; //constants are from offline studies
1080 } else ftime2=sz2; //take the width, not the error
1084 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1087 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1088 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1090 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1091 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1092 if(fNClusters >= fMaxNClusters)
1094 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1095 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1099 fSpacePointData[counter].fX = xyz[0];
1100 // fSpacePointData[counter].fY = xyz[1];
1101 if(fCurrentSlice<18){
1102 fSpacePointData[counter].fY = xyz[1];
1105 fSpacePointData[counter].fY = -1*xyz[1];
1107 fSpacePointData[counter].fZ = xyz[2];
1110 fSpacePointData[counter].fX = fCurrentRow;
1111 fSpacePointData[counter].fY = fpad;
1112 fSpacePointData[counter].fZ = ftime;
1115 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1116 fSpacePointData[counter].fPadRow = fCurrentRow;
1117 fSpacePointData[counter].fSigmaY2 = fpad2;
1118 fSpacePointData[counter].fSigmaZ2 = ftime2;
1120 fSpacePointData[counter].fQMax = list[j].fQMax;
1122 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1123 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1125 Int_t patch=fCurrentPatch;
1126 if(patch==-1) patch=0; //never store negative patch number
1127 fSpacePointData[counter].fID = counter
1128 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1132 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1134 fSpacePointData[counter].fTrackID[0] = trackID[0];
1135 fSpacePointData[counter].fTrackID[1] = trackID[1];
1136 fSpacePointData[counter].fTrackID[2] = trackID[2];
1145 // STILL TO FIX ----------------------------------------------------------------------------
1148 void AliHLTTPCClusterFinder::GetTrackID(Int_t pad,Int_t time,Int_t *trackID){
1149 // see header file for class documentation
1152 AliHLTTPCDigitRowData *rowPt = (AliHLTTPCDigitRowData*)fDigitRowData;
1154 trackID[0]=trackID[1]=trackID[2]=-2;
1155 for(Int_t i=fFirstRow; i<=fLastRow; i++){
1156 if(rowPt->fRow < (UInt_t)fCurrentRow){
1157 AliHLTTPCMemHandler::UpdateRowPointer(rowPt);
1160 AliHLTTPCDigitData *digPt = (AliHLTTPCDigitData*)rowPt->fDigitData;
1161 for(UInt_t j=0; j<rowPt->fNDigit; j++){
1162 Int_t cpad = digPt[j].fPad;
1163 Int_t ctime = digPt[j].fTime;
1164 if(cpad != pad) continue;
1165 if(ctime != time) continue;
1167 trackID[0] = digPt[j].fTrackID[0];
1168 trackID[1] = digPt[j].fTrackID[1];
1169 trackID[2] = digPt[j].fTrackID[2];
1180 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliHLTTPCClusters *list){//This is used when using the AliHLTTPCClusters class for cluster data
1181 // see header file for class documentation
1183 //write cluster to output pointer
1184 Int_t thisrow,thissector;
1185 UInt_t counter = fNClusters;
1187 for(int j=0; j<nclusters; j++)
1189 if(!list[j].fFlags) continue; //discard single pad clusters
1190 if(list[j].fTotalCharge < fThreshold) continue; //noise cluster
1193 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1194 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1195 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1196 Float_t ftime2=fZErr*fZErr; //fixed given error
1199 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1200 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1201 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1202 Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1205 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1206 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1210 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1212 fpad2*=0.108; //constants are from offline studies
1216 } else fpad2=sy2; //take the width not the error
1218 Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1221 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1222 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1226 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1228 ftime2 *= 0.169; //constants are from offline studies
1232 } else ftime2=sz2; //take the width, not the error
1236 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1239 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1240 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1242 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1243 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1244 if(fNClusters >= fMaxNClusters)
1246 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1247 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1251 fSpacePointData[counter].fX = xyz[0];
1252 // fSpacePointData[counter].fY = xyz[1];
1253 if(fCurrentSlice<18){
1254 fSpacePointData[counter].fY = xyz[1];
1257 fSpacePointData[counter].fY = -1*xyz[1];
1259 fSpacePointData[counter].fZ = xyz[2];
1262 fSpacePointData[counter].fX = fCurrentRow;
1263 fSpacePointData[counter].fY = fpad;
1264 fSpacePointData[counter].fZ = ftime;
1267 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1268 fSpacePointData[counter].fPadRow = fCurrentRow;
1269 fSpacePointData[counter].fSigmaY2 = fpad2;
1270 fSpacePointData[counter].fSigmaZ2 = ftime2;
1272 fSpacePointData[counter].fQMax = list[j].fQMax;
1274 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1275 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1277 Int_t patch=fCurrentPatch;
1278 if(patch==-1) patch=0; //never store negative patch number
1279 fSpacePointData[counter].fID = counter
1280 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1284 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1286 fSpacePointData[counter].fTrackID[0] = trackID[0];
1287 fSpacePointData[counter].fTrackID[1] = trackID[1];
1288 fSpacePointData[counter].fTrackID[2] = trackID[2];