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 void AliHLTTPCClusterFinder::InitializePadArray(){
115 // see header file for class documentation
117 if(fCurrentPatch>5||fCurrentPatch<0){
118 HLTFatal("Patch is not set");
122 HLTDebug("Patch number=%d",fCurrentPatch);
124 fFirstRow = AliHLTTPCTransform::GetFirstRow(fCurrentPatch);
125 fLastRow = AliHLTTPCTransform::GetLastRow(fCurrentPatch);
127 fNumberOfRows=fLastRow-fFirstRow+1;
128 fNumberOfPadsInRow= new UInt_t[fNumberOfRows];
130 memset( fNumberOfPadsInRow, 0, sizeof(Int_t)*(fNumberOfRows));
132 for(UInt_t i=0;i<fNumberOfRows;i++){
133 fNumberOfPadsInRow[i]=AliHLTTPCTransform::GetNPads(i+fFirstRow);
134 AliHLTTPCPadVector tmpRow;
135 for(UInt_t j=0;j<=fNumberOfPadsInRow[i];j++){
136 AliHLTTPCPad *tmpPad = new AliHLTTPCPad(2);
138 tmpRow.push_back(tmpPad);
140 fRowPadVector.push_back(tmpRow);
142 fVectorInitialized=kTRUE;
145 Int_t AliHLTTPCClusterFinder::DeInitializePadArray(){
146 // see header file for class documentation
148 for(UInt_t i=0;i<fNumberOfRows;i++){
149 for(UInt_t j=0;j<=fNumberOfPadsInRow[i];j++){
150 delete fRowPadVector[i][j];
151 fRowPadVector[i][j]=NULL;
153 fRowPadVector[i].clear();
155 fRowPadVector.clear();
161 void AliHLTTPCClusterFinder::SetOutputArray(AliHLTTPCSpacePointData *pt){
162 // see header file for class documentation
163 //set pointer to output
164 fSpacePointData = pt;
168 void AliHLTTPCClusterFinder::ReadDataUnsorted(void* ptr,unsigned long size){
169 // see header file for class documentation
171 fPtr = (UChar_t*)ptr;
174 if(!fVectorInitialized){
175 InitializePadArray();
178 if (fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice)<0) {
179 HLTError("failed setting up digit reader (InitBlock)");
183 while(fDigitReader->NextChannel()){
184 UInt_t row=fDigitReader->GetRow();
185 UInt_t pad=fDigitReader->GetPad();
187 if(row>=fRowPadVector.size()){
188 HLTError("Row number is to large: %d, max is %d",row,fRowPadVector.size()-1);
191 if(pad>=fRowPadVector[row].size()){
192 HLTError("Pad number is to large: %d, max is %d",pad,fRowPadVector[row].size());
196 while(fDigitReader->NextBunch()){
197 if(fDigitReader->GetBunchSize()>1){//to remove single timebin values, this will have to change at some point
198 UInt_t time = fDigitReader->GetTime();
199 if((Int_t)time>=fFirstTimeBin && (Int_t)time+fDigitReader->GetBunchSize()<=fLastTimeBin){
200 // Kenneth: 20-04-09. The following if have been added because of inconsistency in the 40 bit decoder and the 32 bit decoder.
201 // GetSignals() in the 40 bit decoder returns an array of UInt_t while the 32 bit one returns UShort_t
202 // The same is true for the function ReadDataUnsortedDeconvoluteTime() below.
203 // In addition the signals are organized in the opposite direction
205 const UShort_t *bunchData= fDigitReader->GetSignalsShort();
206 AliHLTTPCClusters candidate;
207 for(Int_t i=fDigitReader->GetBunchSize()-1;i>=0;i--){
208 candidate.fTotalCharge+=bunchData[i];
209 candidate.fTime += time*bunchData[i];
210 candidate.fTime2 += time*time*bunchData[i];
211 if(bunchData[i]>candidate.fQMax){
212 candidate.fQMax=bunchData[i];
216 if(candidate.fTotalCharge>0){
217 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
218 candidate.fPad=candidate.fTotalCharge*pad;
219 candidate.fPad2=candidate.fPad*pad;
220 candidate.fLastMergedPad=pad;
221 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
223 if(fRowPadVector[row][pad] != NULL){
224 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
228 const UInt_t *bunchData= fDigitReader->GetSignals();
229 AliHLTTPCClusters candidate;
231 const AliHLTTPCDigitData* digits = fDigitReader->GetBunchDigits();
232 for(Int_t i=0;i<fDigitReader->GetBunchSize();i++){
233 candidate.fTotalCharge+=bunchData[i];
234 candidate.fTime += time*bunchData[i];
235 candidate.fTime2 += time*time*bunchData[i];
236 if(bunchData[i]>candidate.fQMax){
237 candidate.fQMax=bunchData[i];
239 fMCDigits.push_back(digits[i]);
244 for(Int_t i=0;i<fDigitReader->GetBunchSize();i++){
245 candidate.fTotalCharge+=bunchData[i];
246 candidate.fTime += time*bunchData[i];
247 candidate.fTime2 += time*time*bunchData[i];
248 if(bunchData[i]>candidate.fQMax){
249 candidate.fQMax=bunchData[i];
254 if(candidate.fTotalCharge>0){
255 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
256 candidate.fPad=candidate.fTotalCharge*pad;
257 candidate.fPad2=candidate.fPad*pad;
258 candidate.fLastMergedPad=pad;
259 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
261 if(fRowPadVector[row][pad] != NULL){
262 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
264 fRowPadVector[row][pad]->AddCandidateDigits(fMCDigits);
275 void AliHLTTPCClusterFinder::ReadDataUnsortedDeconvoluteTime(void* ptr,unsigned long size){
276 // see header file for class documentation
279 fPtr = (UChar_t*)ptr;
282 if(!fVectorInitialized){
283 InitializePadArray();
286 if (fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice)<0) {
287 HLTError("failed setting up digit reader (InitBlock)");
291 while(fDigitReader->NextChannel()){
292 UInt_t row=fDigitReader->GetRow();
293 UInt_t pad=fDigitReader->GetPad();
295 while(fDigitReader->NextBunch()){
296 if(fDigitReader->GetBunchSize()>1){//to remove single timebin values, this will have to change at some point
297 UInt_t time = fDigitReader->GetTime();
298 if((Int_t)time>=fFirstTimeBin && (Int_t)time+fDigitReader->GetBunchSize()<=fLastTimeBin){
299 Int_t indexInBunchData=0;
300 Bool_t moreDataInBunch=kFALSE;
302 Bool_t signalFalling=kFALSE;
304 // Kenneth: 20-04-09. The following if have been added because of inconsistency in the 40 bit decoder and the 32 bit decoder.
305 // GetSignals() in the 40 bit decoder returns an array of UInt_t while the 32 bit one returns UShort_t
306 // The same is true for the function ReadDataUnsorted() above.
307 // In addition the signals are organized in the opposite direction
309 indexInBunchData = fDigitReader->GetBunchSize();
310 const UShort_t *bunchData= fDigitReader->GetSignalsShort();
312 AliHLTTPCClusters candidate;
313 //for(Int_t i=indexInBunchData;i<fDigitReader->GetBunchSize();i++){
314 for(Int_t i=indexInBunchData;i>=0;i--){
315 // Checks if one need to deconvolute the signals
316 if(bunchData[i]>prevSignal && signalFalling==kTRUE){
317 if(i<fDigitReader->GetBunchSize()-1){ // means there are more than one signal left in the bunch
318 moreDataInBunch=kTRUE;
324 // Checks if the signal is 0, then quit processing the data.
325 if(bunchData[i]==0 && i<fDigitReader->GetBunchSize()-1){//means we have 0 data fom the rcu, might happen depending on the configuration settings
326 moreDataInBunch=kTRUE;
331 if(prevSignal>bunchData[i]){//means the peak of the signal has been reached and deconvolution will happen if the signal rise again.
334 candidate.fTotalCharge+=bunchData[i];
335 candidate.fTime += time*bunchData[i];
336 candidate.fTime2 += time*time*bunchData[i];
337 if(bunchData[i]>candidate.fQMax){
338 candidate.fQMax=bunchData[i];
341 prevSignal=bunchData[i];
345 if(candidate.fTotalCharge>0){
346 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
347 candidate.fPad=candidate.fTotalCharge*pad;
348 candidate.fPad2=candidate.fPad*pad;
349 candidate.fLastMergedPad=pad;
350 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
352 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
353 fRowPadVector[row][pad]->AddCandidateDigits(fMCDigits);
354 if(indexInBunchData<fDigitReader->GetBunchSize()-1){
355 moreDataInBunch=kFALSE;
357 }while(moreDataInBunch);
360 const UInt_t *bunchData= fDigitReader->GetSignals();
362 AliHLTTPCClusters candidate;
363 for(Int_t i=indexInBunchData;i<fDigitReader->GetBunchSize();i++){
364 // Checks if one need to deconvolute the signals
365 if(bunchData[i]>prevSignal && signalFalling==kTRUE){
366 if(i<fDigitReader->GetBunchSize()-1){ // means there are more than one signal left in the bunch
367 moreDataInBunch=kTRUE;
373 // Checks if the signal is 0, then quit processing the data.
374 if(bunchData[i]==0 && i<fDigitReader->GetBunchSize()-1){//means we have 0 data fom the rcu, might happen depending on the configuration settings
375 moreDataInBunch=kTRUE;
380 if(prevSignal>bunchData[i]){//means the peak of the signal has been reached and deconvolution will happen if the signal rise again.
383 candidate.fTotalCharge+=bunchData[i];
384 candidate.fTime += time*bunchData[i];
385 candidate.fTime2 += time*time*bunchData[i];
386 if(bunchData[i]>candidate.fQMax){
387 candidate.fQMax=bunchData[i];
390 prevSignal=bunchData[i];
394 if(candidate.fTotalCharge>0){
395 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
396 candidate.fPad=candidate.fTotalCharge*pad;
397 candidate.fPad2=candidate.fPad*pad;
398 candidate.fLastMergedPad=pad;
399 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
401 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
402 if(indexInBunchData<fDigitReader->GetBunchSize()-1){
403 moreDataInBunch=kFALSE;
405 }while(moreDataInBunch);
413 Bool_t AliHLTTPCClusterFinder::ComparePads(AliHLTTPCPad *nextPad,AliHLTTPCClusters* cluster,Int_t nextPadToRead){
414 // see header file for class documentation
416 //Checking if we have a match on the next pad
417 for(UInt_t candidateNumber=0;candidateNumber<nextPad->fClusterCandidates.size();candidateNumber++){
418 AliHLTTPCClusters *candidate =&nextPad->fClusterCandidates[candidateNumber];
419 if(cluster->fMean-candidate->fMean==1 || candidate->fMean-cluster->fMean==1 || cluster->fMean-candidate->fMean==0){
421 if(candidate->fTotalCharge<fTotalChargeOfPreviousClusterCandidate){//peak is reached
422 fChargeOfCandidatesFalling=kTRUE;
424 if(candidate->fTotalCharge>fTotalChargeOfPreviousClusterCandidate && fChargeOfCandidatesFalling==kTRUE){//we have deconvolution
428 cluster->fMean=candidate->fMean;
429 cluster->fTotalCharge+=candidate->fTotalCharge;
430 cluster->fTime += candidate->fTime;
431 cluster->fTime2 += candidate->fTime2;
432 cluster->fPad+=candidate->fPad;
433 cluster->fPad2+=candidate->fPad2;
434 cluster->fLastMergedPad=candidate->fPad;
435 if(candidate->fQMax>cluster->fQMax){
436 cluster->fQMax=candidate->fQMax;
439 FillMCClusterVector(nextPad->GetCandidateDigits(candidateNumber));
443 UInt_t rowNo = nextPad->GetRowNumber();
444 UInt_t padNo = nextPad->GetPadNumber();
446 fRowPadVector[rowNo][padNo-2]->fSelectedPad=kTRUE;
447 fRowPadVector[rowNo][padNo-2]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo-2);
449 fRowPadVector[rowNo][padNo-1]->fSelectedPad=kTRUE;// quick solution to set the first pad to selected
450 fRowPadVector[rowNo][padNo-1]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo-1);
451 fRowPadVector[rowNo][padNo]->fSelectedPad=kTRUE;
452 fRowPadVector[rowNo][padNo]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo);
455 //setting the matched pad to used
456 nextPad->fUsedClusterCandidates[candidateNumber]=1;
458 if(nextPadToRead<(Int_t)fNumberOfPadsInRow[fRowOfFirstCandidate]){
459 nextPad=fRowPadVector[fRowOfFirstCandidate][nextPadToRead];
460 ComparePads(nextPad,cluster,nextPadToRead);
473 Int_t AliHLTTPCClusterFinder::FillHWAddressList(AliHLTUInt16_t *hwaddlist, Int_t maxHWadd){
474 // see header file for class documentation
477 for(UInt_t row=0;row<fNumberOfRows;row++){
478 for(UInt_t pad=0;pad<fNumberOfPadsInRow[row]-1;pad++){
479 if(fRowPadVector[row][pad]->fSelectedPad){
480 if(counter<maxHWadd){
481 hwaddlist[counter]=(AliHLTUInt16_t)fRowPadVector[row][pad]->fHWAddress;
485 HLTWarning("To many hardwareaddresses, skip adding");
495 Int_t AliHLTTPCClusterFinder::FillOutputMCInfo(AliHLTTPCClusterFinder::ClusterMCInfo * outputMCInfo, Int_t maxNumberOfClusterMCInfo){
496 // see header file for class documentation
500 for(UInt_t mc=0;mc<fClustersMCInfo.size();mc++){
501 if(counter<maxNumberOfClusterMCInfo){
502 outputMCInfo[counter] = fClustersMCInfo[mc];
506 HLTWarning("To much MCInfo has been added (no more space), skip adding");
512 void AliHLTTPCClusterFinder::FindClusters(){
513 // see header file for function documentation
515 AliHLTTPCClusters* tmpCandidate=NULL;
516 for(UInt_t row=0;row<fNumberOfRows;row++){
517 fRowOfFirstCandidate=row;
518 for(UInt_t pad=0;pad<fNumberOfPadsInRow[row];pad++){
519 AliHLTTPCPad *tmpPad=fRowPadVector[row][pad];
520 for(size_t candidate=0;candidate<tmpPad->fClusterCandidates.size();candidate++){
521 if(tmpPad->fUsedClusterCandidates[candidate]){
524 tmpCandidate=&tmpPad->fClusterCandidates[candidate];
525 UInt_t tmpTotalCharge=tmpCandidate->fTotalCharge;
528 fClusterMCVector.clear();
529 FillMCClusterVector(tmpPad->GetCandidateDigits(candidate));
532 ComparePads(fRowPadVector[row][pad+1],tmpCandidate,pad+1);
533 if(tmpCandidate->fTotalCharge>tmpTotalCharge){
535 fClusters.push_back(*tmpCandidate);
537 //sort the vector (large->small) according to weight and remove elements above 2 (keep 0 1 and 2)
538 //sort(fClusterMCVector,fClusterMCVector.size(), MCWeight::CompareWeights );
539 ClusterMCInfo tmpClusterMCInfo;
545 if(fClusterMCVector.size()>0){
546 tmpClusterMCInfo.fClusterID[0]=fClusterMCVector.at(0);
549 tmpClusterMCInfo.fClusterID[0]=zeroMC;
552 if(fClusterMCVector.size()>1){
553 tmpClusterMCInfo.fClusterID[1]=fClusterMCVector.at(1);
556 tmpClusterMCInfo.fClusterID[1]=zeroMC;
559 if(fClusterMCVector.size()>2){
560 tmpClusterMCInfo.fClusterID[2]=fClusterMCVector.at(2);
563 tmpClusterMCInfo.fClusterID[2]=zeroMC;
566 fClustersMCInfo.push_back(tmpClusterMCInfo);
571 tmpPad->ClearCandidates();
573 fRowPadVector[row][fNumberOfPadsInRow[row]]->ClearCandidates();
576 HLTInfo("Found %d clusters.",fClusters.size());
578 //TODO: Change so it stores AliHLTTPCSpacePointData directly, instead of this copying
580 AliClusterData * clusterlist = new AliClusterData[fClusters.size()]; //Clusterlist
581 for(unsigned int i=0;i<fClusters.size();i++){
582 clusterlist[i].fTotalCharge = fClusters[i].fTotalCharge;
583 clusterlist[i].fPad = fClusters[i].fPad;
584 clusterlist[i].fPad2 = fClusters[i].fPad2;
585 clusterlist[i].fTime = fClusters[i].fTime;
586 clusterlist[i].fTime2 = fClusters[i].fTime2;
587 clusterlist[i].fMean = fClusters[i].fMean;
588 clusterlist[i].fFlags = fClusters[i].fFlags;
589 clusterlist[i].fChargeFalling = fClusters[i].fChargeFalling;
590 clusterlist[i].fLastCharge = fClusters[i].fLastCharge;
591 clusterlist[i].fLastMergedPad = fClusters[i].fLastMergedPad;
592 clusterlist[i].fRow = fClusters[i].fRowNumber;
593 clusterlist[i].fQMax = fClusters[i].fQMax;
596 WriteClusters(fClusters.size(),clusterlist);
597 delete [] clusterlist;
602 //---------------------------------- Under this line the old sorted clusterfinder functions can be found --------------------------------
605 void AliHLTTPCClusterFinder::PrintClusters(){
606 // see header file for class documentation
608 for(size_t i=0;i<fClusters.size();i++){
609 HLTInfo("Cluster number: %d",i);
610 HLTInfo("Row: %d \t Pad: %d",fClusters[i].fRowNumber,fClusters[i].fPad/fClusters[i].fTotalCharge);
611 HLTInfo("Total Charge: %d",fClusters[i].fTotalCharge);
612 HLTInfo("fPad: %d",fClusters[i].fPad);
613 HLTInfo("PadError: %d",fClusters[i].fPad2);
614 HLTInfo("TimeMean: %d",fClusters[i].fTime/fClusters[i].fTotalCharge);
615 HLTInfo("TimeError: %d",fClusters[i].fTime2);
616 HLTInfo("EndOfCluster:");
620 void AliHLTTPCClusterFinder::FillMCClusterVector(vector<AliHLTTPCDigitData> digitData){
622 for(UInt_t d=0;d<digitData.size();d++){
623 Int_t nIDsInDigit = (digitData.at(d).fTrackID[0]>=0) + (digitData.at(d).fTrackID[1]>=0) + (digitData.at(d).fTrackID[2]>=0);
624 for(Int_t id=0; id<3; id++){
625 if(digitData.at(d).fTrackID[id]>=0){
626 Bool_t matchFound = kFALSE;
628 mc.fMCID = digitData.at(d).fTrackID[id];
629 mc.fWeight = ((Float_t)digitData.at(d).fCharge)/nIDsInDigit;
630 for(UInt_t i=0;i<fClusterMCVector.size();i++){
631 if(mc.fMCID == fClusterMCVector.at(i).fMCID){
632 fClusterMCVector.at(i).fWeight += mc.fWeight;
636 if(matchFound == kFALSE){
637 fClusterMCVector.push_back(mc);
645 void AliHLTTPCClusterFinder::Read(void* ptr,unsigned long size){
647 fPtr = (UChar_t*)ptr;
651 void AliHLTTPCClusterFinder::ProcessDigits(){
652 // see header file for class documentation
655 bool readValue = true;
658 UShort_t time=0,newTime=0;
659 UInt_t pad=0,newPad=0;
660 AliHLTTPCSignal_t charge=0;
664 // initialize block for reading packed data
665 iResult=fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice);
666 if (iResult<0) return;
668 readValue = fDigitReader->Next();
670 // Matthias 08.11.2006 the following return would cause termination without writing the
671 // ClusterData and thus would block the component. I just want to have the commented line
672 // here for information
673 //if (!readValue)return;
675 pad = fDigitReader->GetPad();
676 time = fDigitReader->GetTime();
677 fCurrentRow = fDigitReader->GetRow();
679 if ( fCurrentPatch >= 2 ) // Outer sector, patches 2, 3, 4, 5
680 rowOffset = AliHLTTPCTransform::GetFirstRow( 2 );
682 fCurrentRow += rowOffset;
684 UInt_t lastpad = 123456789;
685 const UInt_t kPadArraySize=5000;
686 const UInt_t kClusterListSize=10000;
687 AliClusterData *pad1[kPadArraySize]; //2 lists for internal memory=2pads
688 AliClusterData *pad2[kPadArraySize]; //2 lists for internal memory=2pads
689 AliClusterData clusterlist[kClusterListSize]; //Clusterlist
691 AliClusterData **currentPt; //List of pointers to the current pad
692 AliClusterData **previousPt; //List of pointers to the previous pad
695 UInt_t nprevious=0,ncurrent=0,ntotal=0;
697 /* quick implementation of baseline calculation and zero suppression
698 open a pad object for each pad and delete it after processing.
699 later a list of pad objects with base line history can be used
700 The whole thing only works if we really get unprocessed raw data, if
701 the data is already zero suppressed, there might be gaps in the time
704 Int_t gatingGridOffset=50;
706 gatingGridOffset=fFirstTimeBin;
708 AliHLTTPCPad baseline(gatingGridOffset, AliHLTTPCTransform::GetNTimeBins());
709 // just to make later conversion to a list of objects easier
710 AliHLTTPCPad* pCurrentPad=NULL;
712 if (fSignalThreshold>=0) {
713 pCurrentPad=&baseline;
714 baseline.SetThreshold(fSignalThreshold);
717 while ( readValue!=0 && iResult>=0){ // Reads through all digits in block
724 if(currentPt == pad2){
732 nprevious = ncurrent;
734 if(pad != lastpad+1){
735 //this happens if there is a pad with no signal.
736 nprevious = ncurrent = 0;
741 Bool_t newcluster = kTRUE;
742 UInt_t seqcharge=0,seqaverage=0,seqerror=0;
743 AliHLTTPCSignal_t lastcharge=0;
744 UInt_t bLastWasFalling=0;
749 redo: //This is a goto.
760 while(iResult>=0){ //Loop over time bins of current pad
761 // read all the values for one pad at once to calculate the base line
763 if (!pCurrentPad->IsStarted()) {
764 //HLTDebug("reading data for pad %d, padrow %d", fDigitReader->GetPad(), fDigitReader->GetRow()+rowOffset);
765 pCurrentPad->SetID(fDigitReader->GetRow()+rowOffset,fDigitReader->GetPad());
766 if ((pCurrentPad->StartEvent())>=0) {
768 if ((fDigitReader->GetRow()+rowOffset)!=pCurrentPad->GetRowNumber()) break;
769 if (fDigitReader->GetPad()!=pCurrentPad->GetPadNumber()) break;
770 pCurrentPad->SetRawData(fDigitReader->GetTime(), fDigitReader->GetSignal());
771 //HLTDebug("set raw data to pad: bin %d charge %d", fDigitReader->GetTime(), fDigitReader->GetSignal());
772 } while ((readValue = fDigitReader->Next())!=0);
774 pCurrentPad->CalculateBaseLine(AliHLTTPCTransform::GetNTimeBins()/2);
775 if (pCurrentPad->Next(kTRUE/*do zero suppression*/)==0) {
776 //HLTDebug("no data available after zero suppression");
777 pCurrentPad->StopEvent();
778 pCurrentPad->ResetHistory();
781 time=pCurrentPad->GetCurrentPosition();
782 if (time>pCurrentPad->GetSize()) {
783 HLTError("invalid time bin for pad");
789 Float_t occupancy=pCurrentPad->GetOccupancy();
790 //HLTDebug("pad %d occupancy level: %f", pCurrentPad->GetPadNumber(), occupancy);
791 if ( occupancy < fOccupancyLimit ) {
792 charge = pCurrentPad->GetCorrectedData();
795 //HLTDebug("ignoring pad %d with occupancy level %f", pCurrentPad->GetPadNumber(), occupancy);
798 charge = fDigitReader->GetSignal();
800 //HLTDebug("get next charge value: position %d charge %d", time, charge);
804 if (fDigitReader->GetRow() == 90){
805 ///// LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::Row","row90") << "PAD=" << fDigitReader->GetPad() << " TIME=" << fDigitReader->GetTime()
806 // << " SIGNAL=" << fDigitReader->GetSignal() << ENDLOG;
810 if(time >= AliHLTTPCTransform::GetNTimeBins()){
811 HLTWarning("Pad %d: Timebin (%d) out of range (%d)", pad, time, AliHLTTPCTransform::GetNTimeBins());
816 //Get the current ADC-value
819 //Check if the last pixel in the sequence is smaller than this
820 if(charge > lastcharge){
826 else bLastWasFalling = 1; //last pixel was larger than this
830 //Sum the total charge of this sequence
832 seqaverage += time*charge;
833 seqerror += time*time*charge;
837 if((pCurrentPad->Next(kTRUE/*do zero suppression*/))==0) {
838 pCurrentPad->StopEvent();
839 pCurrentPad->ResetHistory();
841 newPad = fDigitReader->GetPad();
842 newTime = fDigitReader->GetTime();
843 newRow = fDigitReader->GetRow() + rowOffset;
848 newPad=pCurrentPad->GetPadNumber();
849 newTime=pCurrentPad->GetCurrentPosition();
850 newRow=pCurrentPad->GetRowNumber();
852 readValue = fDigitReader->Next();
853 //Check where to stop:
854 if(!readValue) break; //No more value
856 newPad = fDigitReader->GetPad();
857 newTime = fDigitReader->GetTime();
858 newRow = fDigitReader->GetRow() + rowOffset;
861 if(newPad != pad)break; //new pad
862 if(newTime != time+1) break; //end of sequence
865 // pad = newpad; is equal
868 }//end loop over sequence
870 //HLTDebug("ended time bin sequence loop: seqcharge=%d readValue=%d", seqcharge, readValue);
871 //HLTDebug("pad=%d newpad=%d current row=%d newrow=%d", pad, newPad, fCurrentRow, newRow);
873 // with active zero suppression zero values are possible
877 //Calculate mean of sequence:
880 seqmean = seqaverage/seqcharge;
882 LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::ProcessRow","Data")
883 <<"Error in data given to the cluster finder"<<ENDLOG;
888 //Calculate mean in pad direction:
889 Int_t padmean = seqcharge*pad;
890 Int_t paderror = pad*padmean;
892 //Compare with results on previous pad:
893 for(UInt_t p=0; p<nprevious && p<kPadArraySize && ncurrent<kPadArraySize; p++){
895 //dont merge sequences on the same pad twice
896 if(previousPt[p]->fLastMergedPad==pad) continue;
898 Int_t difference = seqmean - previousPt[p]->fMean;
899 if(difference < -fMatch) break;
901 if(difference <= fMatch){ //There is a match here!!
902 AliClusterData *local = previousPt[p];
905 if(seqcharge > local->fLastCharge){
906 if(local->fChargeFalling){ //The previous pad was falling
907 break; //create a new cluster
910 else local->fChargeFalling = 1;
911 local->fLastCharge = seqcharge;
914 //Don't create a new cluster, because we found a match
917 //Update cluster on current pad with the matching one:
918 local->fTotalCharge += seqcharge;
919 local->fPad += padmean;
920 local->fPad2 += paderror;
921 local->fTime += seqaverage;
922 local->fTime2 += seqerror;
923 local->fMean = seqmean;
924 local->fFlags++; //means we have more than one pad
925 local->fLastMergedPad = pad;
927 currentPt[ncurrent] = local;
931 } //Checking for match at previous pad
932 } //Loop over results on previous pad.
934 if(newcluster && ncurrent<kPadArraySize){
935 //Start a new cluster. Add it to the clusterlist, and update
936 //the list of pointers to clusters in current pad.
937 //current pad will be previous pad on next pad.
939 //Add to the clusterlist:
940 AliClusterData *tmp = &clusterlist[ntotal];
941 tmp->fTotalCharge = seqcharge;
943 tmp->fPad2 = paderror;
944 tmp->fTime = seqaverage;
945 tmp->fTime2 = seqerror;
946 tmp->fMean = seqmean;
947 tmp->fFlags = 0; //flags for single pad clusters
948 tmp->fLastMergedPad = pad;
951 tmp->fChargeFalling = 0;
952 tmp->fLastCharge = seqcharge;
955 //Update list of pointers to previous pad:
956 currentPt[ncurrent] = &clusterlist[ntotal];
962 if(newbin >= 0) goto redo;
964 // to prevent endless loop
965 if(time >= AliHLTTPCTransform::GetNTimeBins()){
966 HLTWarning("Timebin (%d) out of range (%d)", time, AliHLTTPCTransform::GetNTimeBins());
971 if(!readValue) break; //No more value
973 if (ntotal>=kClusterListSize || ncurrent>=kPadArraySize) {
974 HLTWarning("pad array size exceeded ntotal=%d ncurrent=%d, skip rest of the data", ntotal, ncurrent);
978 if(fCurrentRow != newRow){
979 WriteClusters(ntotal,clusterlist);
989 fCurrentRow = newRow;
995 } // END while(readValue)
997 WriteClusters(ntotal,clusterlist);
999 HLTInfo("ClusterFinder found %d clusters in slice %d patch %d", fNClusters, fCurrentSlice, fCurrentPatch);
1003 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliClusterData *list){
1004 // see header file for class documentation
1006 //write cluster to output pointer
1007 Int_t thisrow=-1,thissector=-1;
1008 UInt_t counter = fNClusters;
1010 for(int j=0; j<nclusters; j++)
1015 if(!list[j].fFlags){
1017 fClustersMCInfo.erase(fClustersMCInfo.begin()+j); // remove the mc ifo for this cluster since it is not taken into account
1019 continue; //discard single pad clusters
1021 if(list[j].fTotalCharge < fThreshold){
1023 fClustersMCInfo.erase(fClustersMCInfo.begin()+j); // remove the mc ifo for this cluster since it is not taken into account
1025 continue; //noise cluster
1028 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1029 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1030 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1031 Float_t ftime2=fZErr*fZErr; //fixed given error
1036 fCurrentRow=list[j].fRow;
1040 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1041 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1042 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1043 // Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1044 Float_t sy2=(Float_t)list[j].fPad2 * list[j].fTotalCharge - (Float_t)list[j].fPad * list[j].fPad;
1047 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1048 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1052 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1054 fpad2*=0.108; //constants are from offline studies
1058 } else fpad2=sy2; //take the width not the error
1060 // Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1061 Float_t sz2=(Float_t)list[j].fTime2*list[j].fTotalCharge - (Float_t)list[j].fTime*list[j].fTime;
1064 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1065 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1069 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1071 ftime2 *= 0.169; //constants are from offline studies
1075 } else ftime2=sz2; //take the width, not the error
1079 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1082 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1083 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1085 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1086 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1087 if(fNClusters >= fMaxNClusters)
1089 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1090 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1094 fSpacePointData[counter].fX = xyz[0];
1095 // fSpacePointData[counter].fY = xyz[1];
1096 if(fCurrentSlice<18){
1097 fSpacePointData[counter].fY = xyz[1];
1100 fSpacePointData[counter].fY = -1*xyz[1];
1102 fSpacePointData[counter].fZ = xyz[2];
1105 fSpacePointData[counter].fX = fCurrentRow;
1106 fSpacePointData[counter].fY = fpad;
1107 fSpacePointData[counter].fZ = ftime;
1110 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1111 fSpacePointData[counter].fPadRow = fCurrentRow;
1112 fSpacePointData[counter].fSigmaY2 = fpad2;
1113 fSpacePointData[counter].fSigmaZ2 = ftime2;
1115 fSpacePointData[counter].fQMax = list[j].fQMax;
1117 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1118 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1120 Int_t patch=fCurrentPatch;
1121 if(patch==-1) patch=0; //never store negative patch number
1122 fSpacePointData[counter].fID = counter
1123 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1127 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1129 fSpacePointData[counter].fTrackID[0] = trackID[0];
1130 fSpacePointData[counter].fTrackID[1] = trackID[1];
1131 fSpacePointData[counter].fTrackID[2] = trackID[2];
1140 // STILL TO FIX ----------------------------------------------------------------------------
1143 void AliHLTTPCClusterFinder::GetTrackID(Int_t pad,Int_t time,Int_t *trackID){
1144 // see header file for class documentation
1147 AliHLTTPCDigitRowData *rowPt = (AliHLTTPCDigitRowData*)fDigitRowData;
1149 trackID[0]=trackID[1]=trackID[2]=-2;
1150 for(Int_t i=fFirstRow; i<=fLastRow; i++){
1151 if(rowPt->fRow < (UInt_t)fCurrentRow){
1152 AliHLTTPCMemHandler::UpdateRowPointer(rowPt);
1155 AliHLTTPCDigitData *digPt = (AliHLTTPCDigitData*)rowPt->fDigitData;
1156 for(UInt_t j=0; j<rowPt->fNDigit; j++){
1157 Int_t cpad = digPt[j].fPad;
1158 Int_t ctime = digPt[j].fTime;
1159 if(cpad != pad) continue;
1160 if(ctime != time) continue;
1162 trackID[0] = digPt[j].fTrackID[0];
1163 trackID[1] = digPt[j].fTrackID[1];
1164 trackID[2] = digPt[j].fTrackID[2];
1175 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliHLTTPCClusters *list){//This is used when using the AliHLTTPCClusters class for cluster data
1176 // see header file for class documentation
1178 //write cluster to output pointer
1179 Int_t thisrow,thissector;
1180 UInt_t counter = fNClusters;
1182 for(int j=0; j<nclusters; j++)
1184 if(!list[j].fFlags) continue; //discard single pad clusters
1185 if(list[j].fTotalCharge < fThreshold) continue; //noise cluster
1188 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1189 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1190 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1191 Float_t ftime2=fZErr*fZErr; //fixed given error
1194 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1195 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1196 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1197 Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1200 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1201 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1205 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1207 fpad2*=0.108; //constants are from offline studies
1211 } else fpad2=sy2; //take the width not the error
1213 Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1216 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1217 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1221 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1223 ftime2 *= 0.169; //constants are from offline studies
1227 } else ftime2=sz2; //take the width, not the error
1231 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1234 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1235 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1237 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1238 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1239 if(fNClusters >= fMaxNClusters)
1241 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1242 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1246 fSpacePointData[counter].fX = xyz[0];
1247 // fSpacePointData[counter].fY = xyz[1];
1248 if(fCurrentSlice<18){
1249 fSpacePointData[counter].fY = xyz[1];
1252 fSpacePointData[counter].fY = -1*xyz[1];
1254 fSpacePointData[counter].fZ = xyz[2];
1257 fSpacePointData[counter].fX = fCurrentRow;
1258 fSpacePointData[counter].fY = fpad;
1259 fSpacePointData[counter].fZ = ftime;
1262 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1263 fSpacePointData[counter].fPadRow = fCurrentRow;
1264 fSpacePointData[counter].fSigmaY2 = fpad2;
1265 fSpacePointData[counter].fSigmaZ2 = ftime2;
1267 fSpacePointData[counter].fQMax = list[j].fQMax;
1269 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1270 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1272 Int_t patch=fCurrentPatch;
1273 if(patch==-1) patch=0; //never store negative patch number
1274 fSpacePointData[counter].fID = counter
1275 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1279 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1281 fSpacePointData[counter].fTrackID[0] = trackID[0];
1282 fSpacePointData[counter].fTrackID[1] = trackID[1];
1283 fSpacePointData[counter].fTrackID[2] = trackID[2];