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){
668 // see header file for class documentation
670 for(UInt_t d=0;d<digitData.size();d++){
671 Int_t nIDsInDigit = (digitData.at(d).fTrackID[0]>=0) + (digitData.at(d).fTrackID[1]>=0) + (digitData.at(d).fTrackID[2]>=0);
672 for(Int_t id=0; id<3; id++){
673 if(digitData.at(d).fTrackID[id]>=0){
674 Bool_t matchFound = kFALSE;
676 mc.fMCID = digitData.at(d).fTrackID[id];
677 mc.fWeight = ((Float_t)digitData.at(d).fCharge)/nIDsInDigit;
678 for(UInt_t i=0;i<fClusterMCVector.size();i++){
679 if(mc.fMCID == fClusterMCVector.at(i).fMCID){
680 fClusterMCVector.at(i).fWeight += mc.fWeight;
684 if(matchFound == kFALSE){
685 fClusterMCVector.push_back(mc);
693 void AliHLTTPCClusterFinder::Read(void* ptr,unsigned long size){
695 fPtr = (UChar_t*)ptr;
699 void AliHLTTPCClusterFinder::ProcessDigits(){
700 // see header file for class documentation
703 bool readValue = true;
706 UShort_t time=0,newTime=0;
707 UInt_t pad=0,newPad=0;
708 AliHLTTPCSignal_t charge=0;
712 // initialize block for reading packed data
713 iResult=fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice);
714 if (iResult<0) return;
716 readValue = fDigitReader->Next();
718 // Matthias 08.11.2006 the following return would cause termination without writing the
719 // ClusterData and thus would block the component. I just want to have the commented line
720 // here for information
721 //if (!readValue)return;
723 pad = fDigitReader->GetPad();
724 time = fDigitReader->GetTime();
725 fCurrentRow = fDigitReader->GetRow();
727 if ( fCurrentPatch >= 2 ) // Outer sector, patches 2, 3, 4, 5
728 rowOffset = AliHLTTPCTransform::GetFirstRow( 2 );
730 fCurrentRow += rowOffset;
732 UInt_t lastpad = 123456789;
733 const UInt_t kPadArraySize=5000;
734 const UInt_t kClusterListSize=10000;
735 AliClusterData *pad1[kPadArraySize]; //2 lists for internal memory=2pads
736 AliClusterData *pad2[kPadArraySize]; //2 lists for internal memory=2pads
737 AliClusterData clusterlist[kClusterListSize]; //Clusterlist
739 AliClusterData **currentPt; //List of pointers to the current pad
740 AliClusterData **previousPt; //List of pointers to the previous pad
743 UInt_t nprevious=0,ncurrent=0,ntotal=0;
745 /* quick implementation of baseline calculation and zero suppression
746 open a pad object for each pad and delete it after processing.
747 later a list of pad objects with base line history can be used
748 The whole thing only works if we really get unprocessed raw data, if
749 the data is already zero suppressed, there might be gaps in the time
752 Int_t gatingGridOffset=50;
754 gatingGridOffset=fFirstTimeBin;
756 AliHLTTPCPad baseline(gatingGridOffset, AliHLTTPCTransform::GetNTimeBins());
757 // just to make later conversion to a list of objects easier
758 AliHLTTPCPad* pCurrentPad=NULL;
760 if (fSignalThreshold>=0) {
761 pCurrentPad=&baseline;
762 baseline.SetThreshold(fSignalThreshold);
765 while ( readValue!=0 && iResult>=0){ // Reads through all digits in block
772 if(currentPt == pad2){
780 nprevious = ncurrent;
782 if(pad != lastpad+1){
783 //this happens if there is a pad with no signal.
784 nprevious = ncurrent = 0;
789 Bool_t newcluster = kTRUE;
790 UInt_t seqcharge=0,seqaverage=0,seqerror=0;
791 AliHLTTPCSignal_t lastcharge=0;
792 UInt_t bLastWasFalling=0;
797 redo: //This is a goto.
808 while(iResult>=0){ //Loop over time bins of current pad
809 // read all the values for one pad at once to calculate the base line
811 if (!pCurrentPad->IsStarted()) {
812 //HLTDebug("reading data for pad %d, padrow %d", fDigitReader->GetPad(), fDigitReader->GetRow()+rowOffset);
813 pCurrentPad->SetID(fDigitReader->GetRow()+rowOffset,fDigitReader->GetPad());
814 if ((pCurrentPad->StartEvent())>=0) {
816 if ((fDigitReader->GetRow()+rowOffset)!=pCurrentPad->GetRowNumber()) break;
817 if (fDigitReader->GetPad()!=pCurrentPad->GetPadNumber()) break;
818 pCurrentPad->SetRawData(fDigitReader->GetTime(), fDigitReader->GetSignal());
819 //HLTDebug("set raw data to pad: bin %d charge %d", fDigitReader->GetTime(), fDigitReader->GetSignal());
820 } while ((readValue = fDigitReader->Next())!=0);
822 pCurrentPad->CalculateBaseLine(AliHLTTPCTransform::GetNTimeBins()/2);
823 if (pCurrentPad->Next(kTRUE/*do zero suppression*/)==0) {
824 //HLTDebug("no data available after zero suppression");
825 pCurrentPad->StopEvent();
826 pCurrentPad->ResetHistory();
829 time=pCurrentPad->GetCurrentPosition();
830 if (time>pCurrentPad->GetSize()) {
831 HLTError("invalid time bin for pad");
837 Float_t occupancy=pCurrentPad->GetOccupancy();
838 //HLTDebug("pad %d occupancy level: %f", pCurrentPad->GetPadNumber(), occupancy);
839 if ( occupancy < fOccupancyLimit ) {
840 charge = pCurrentPad->GetCorrectedData();
843 //HLTDebug("ignoring pad %d with occupancy level %f", pCurrentPad->GetPadNumber(), occupancy);
846 charge = fDigitReader->GetSignal();
848 //HLTDebug("get next charge value: position %d charge %d", time, charge);
852 if (fDigitReader->GetRow() == 90){
853 ///// LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::Row","row90") << "PAD=" << fDigitReader->GetPad() << " TIME=" << fDigitReader->GetTime()
854 // << " SIGNAL=" << fDigitReader->GetSignal() << ENDLOG;
858 if(time >= AliHLTTPCTransform::GetNTimeBins()){
859 HLTWarning("Pad %d: Timebin (%d) out of range (%d)", pad, time, AliHLTTPCTransform::GetNTimeBins());
864 //Get the current ADC-value
867 //Check if the last pixel in the sequence is smaller than this
868 if(charge > lastcharge){
874 else bLastWasFalling = 1; //last pixel was larger than this
878 //Sum the total charge of this sequence
880 seqaverage += time*charge;
881 seqerror += time*time*charge;
885 if((pCurrentPad->Next(kTRUE/*do zero suppression*/))==0) {
886 pCurrentPad->StopEvent();
887 pCurrentPad->ResetHistory();
889 newPad = fDigitReader->GetPad();
890 newTime = fDigitReader->GetTime();
891 newRow = fDigitReader->GetRow() + rowOffset;
896 newPad=pCurrentPad->GetPadNumber();
897 newTime=pCurrentPad->GetCurrentPosition();
898 newRow=pCurrentPad->GetRowNumber();
900 readValue = fDigitReader->Next();
901 //Check where to stop:
902 if(!readValue) break; //No more value
904 newPad = fDigitReader->GetPad();
905 newTime = fDigitReader->GetTime();
906 newRow = fDigitReader->GetRow() + rowOffset;
909 if(newPad != pad)break; //new pad
910 if(newTime != time+1) break; //end of sequence
913 // pad = newpad; is equal
916 }//end loop over sequence
918 //HLTDebug("ended time bin sequence loop: seqcharge=%d readValue=%d", seqcharge, readValue);
919 //HLTDebug("pad=%d newpad=%d current row=%d newrow=%d", pad, newPad, fCurrentRow, newRow);
921 // with active zero suppression zero values are possible
925 //Calculate mean of sequence:
928 seqmean = seqaverage/seqcharge;
930 LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::ProcessRow","Data")
931 <<"Error in data given to the cluster finder"<<ENDLOG;
936 //Calculate mean in pad direction:
937 Int_t padmean = seqcharge*pad;
938 Int_t paderror = pad*padmean;
940 //Compare with results on previous pad:
941 for(UInt_t p=0; p<nprevious && p<kPadArraySize && ncurrent<kPadArraySize; p++){
943 //dont merge sequences on the same pad twice
944 if(previousPt[p]->fLastMergedPad==pad) continue;
946 Int_t difference = seqmean - previousPt[p]->fMean;
947 if(difference < -fMatch) break;
949 if(difference <= fMatch){ //There is a match here!!
950 AliClusterData *local = previousPt[p];
953 if(seqcharge > local->fLastCharge){
954 if(local->fChargeFalling){ //The previous pad was falling
955 break; //create a new cluster
958 else local->fChargeFalling = 1;
959 local->fLastCharge = seqcharge;
962 //Don't create a new cluster, because we found a match
965 //Update cluster on current pad with the matching one:
966 local->fTotalCharge += seqcharge;
967 local->fPad += padmean;
968 local->fPad2 += paderror;
969 local->fTime += seqaverage;
970 local->fTime2 += seqerror;
971 local->fMean = seqmean;
972 local->fFlags++; //means we have more than one pad
973 local->fLastMergedPad = pad;
975 currentPt[ncurrent] = local;
979 } //Checking for match at previous pad
980 } //Loop over results on previous pad.
982 if(newcluster && ncurrent<kPadArraySize){
983 //Start a new cluster. Add it to the clusterlist, and update
984 //the list of pointers to clusters in current pad.
985 //current pad will be previous pad on next pad.
987 //Add to the clusterlist:
988 AliClusterData *tmp = &clusterlist[ntotal];
989 tmp->fTotalCharge = seqcharge;
991 tmp->fPad2 = paderror;
992 tmp->fTime = seqaverage;
993 tmp->fTime2 = seqerror;
994 tmp->fMean = seqmean;
995 tmp->fFlags = 0; //flags for single pad clusters
996 tmp->fLastMergedPad = pad;
999 tmp->fChargeFalling = 0;
1000 tmp->fLastCharge = seqcharge;
1003 //Update list of pointers to previous pad:
1004 currentPt[ncurrent] = &clusterlist[ntotal];
1010 if(newbin >= 0) goto redo;
1012 // to prevent endless loop
1013 if(time >= AliHLTTPCTransform::GetNTimeBins()){
1014 HLTWarning("Timebin (%d) out of range (%d)", time, AliHLTTPCTransform::GetNTimeBins());
1019 if(!readValue) break; //No more value
1021 if (ntotal>=kClusterListSize || ncurrent>=kPadArraySize) {
1022 HLTWarning("pad array size exceeded ntotal=%d ncurrent=%d, skip rest of the data", ntotal, ncurrent);
1026 if(fCurrentRow != newRow){
1027 WriteClusters(ntotal,clusterlist);
1029 lastpad = 123456789;
1037 fCurrentRow = newRow;
1043 } // END while(readValue)
1045 WriteClusters(ntotal,clusterlist);
1047 HLTInfo("ClusterFinder found %d clusters in slice %d patch %d", fNClusters, fCurrentSlice, fCurrentPatch);
1051 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliClusterData *list){
1052 // see header file for class documentation
1054 //write cluster to output pointer
1055 Int_t thisrow=-1,thissector=-1;
1056 UInt_t counter = fNClusters;
1058 for(int j=0; j<nclusters; j++)
1063 if(!list[j].fFlags){
1065 if(j+(Int_t)fClustersMCInfo.size()-nclusters >=0 && j+fClustersMCInfo.size()-nclusters < fClustersMCInfo.size()){
1066 fClustersMCInfo.erase(fClustersMCInfo.begin()+j+fClustersMCInfo.size()-nclusters); // remove the mc info for this cluster since it is not taken into account
1069 continue; //discard single pad clusters
1071 if(list[j].fTotalCharge < fThreshold){
1073 if(j+(Int_t)fClustersMCInfo.size()-nclusters >=0 && j+fClustersMCInfo.size()-nclusters < fClustersMCInfo.size()){
1074 fClustersMCInfo.erase(fClustersMCInfo.begin()+j+fClustersMCInfo.size()-nclusters); // remove the mc info for this cluster since it is not taken into account
1077 continue; //noise cluster
1080 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1081 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1082 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1083 Float_t ftime2=fZErr*fZErr; //fixed given error
1088 fCurrentRow=list[j].fRow;
1092 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1093 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1094 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1095 // Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1096 Float_t sy2=(Float_t)list[j].fPad2 * list[j].fTotalCharge - (Float_t)list[j].fPad * list[j].fPad;
1099 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1100 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1104 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1106 fpad2*=0.108; //constants are from offline studies
1110 } else fpad2=sy2; //take the width not the error
1112 // Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1113 Float_t sz2=(Float_t)list[j].fTime2*list[j].fTotalCharge - (Float_t)list[j].fTime*list[j].fTime;
1116 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1117 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1121 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1123 ftime2 *= 0.169; //constants are from offline studies
1127 } else ftime2=sz2; //take the width, not the error
1131 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1134 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1136 if(fOfflineTransform == NULL){
1137 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1139 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1140 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1141 if(fNClusters >= fMaxNClusters)
1143 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1144 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1148 fSpacePointData[counter].fX = xyz[0];
1149 // fSpacePointData[counter].fY = xyz[1];
1150 if(fCurrentSlice<18){
1151 fSpacePointData[counter].fY = xyz[1];
1154 fSpacePointData[counter].fY = -1*xyz[1];
1156 fSpacePointData[counter].fZ = xyz[2];
1159 Double_t x[3]={thisrow,fpad+.5,ftime};
1160 Int_t iSector[1]={thissector};
1161 fOfflineTransform->Transform(x,iSector,0,1);
1162 fSpacePointData[counter].fX = x[0];
1163 fSpacePointData[counter].fY = x[1];
1164 fSpacePointData[counter].fZ = x[2];
1169 fSpacePointData[counter].fX = fCurrentRow;
1170 fSpacePointData[counter].fY = fpad;
1171 fSpacePointData[counter].fZ = ftime;
1174 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1175 fSpacePointData[counter].fPadRow = fCurrentRow;
1176 fSpacePointData[counter].fSigmaY2 = fpad2;
1177 fSpacePointData[counter].fSigmaZ2 = ftime2;
1179 fSpacePointData[counter].fQMax = list[j].fQMax;
1181 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1182 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1184 Int_t patch=fCurrentPatch;
1185 if(patch==-1) patch=0; //never store negative patch number
1186 fSpacePointData[counter].fID = counter
1187 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1191 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1193 fSpacePointData[counter].fTrackID[0] = trackID[0];
1194 fSpacePointData[counter].fTrackID[1] = trackID[1];
1195 fSpacePointData[counter].fTrackID[2] = trackID[2];
1204 // STILL TO FIX ----------------------------------------------------------------------------
1207 void AliHLTTPCClusterFinder::GetTrackID(Int_t pad,Int_t time,Int_t *trackID) const {
1208 // see header file for class documentation
1211 AliHLTTPCDigitRowData *rowPt = (AliHLTTPCDigitRowData*)fDigitRowData;
1213 trackID[0]=trackID[1]=trackID[2]=-2;
1214 for(Int_t i=fFirstRow; i<=fLastRow; i++){
1215 if(rowPt->fRow < (UInt_t)fCurrentRow){
1216 AliHLTTPCMemHandler::UpdateRowPointer(rowPt);
1219 AliHLTTPCDigitData *digPt = (AliHLTTPCDigitData*)rowPt->fDigitData;
1220 for(UInt_t j=0; j<rowPt->fNDigit; j++){
1221 Int_t cpad = digPt[j].fPad;
1222 Int_t ctime = digPt[j].fTime;
1223 if(cpad != pad) continue;
1224 if(ctime != time) continue;
1226 trackID[0] = digPt[j].fTrackID[0];
1227 trackID[1] = digPt[j].fTrackID[1];
1228 trackID[2] = digPt[j].fTrackID[2];
1239 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliHLTTPCClusters *list){//This is used when using the AliHLTTPCClusters class for cluster data
1240 // see header file for class documentation
1242 //write cluster to output pointer
1243 Int_t thisrow,thissector;
1244 UInt_t counter = fNClusters;
1246 for(int j=0; j<nclusters; j++)
1248 if(!list[j].fFlags) continue; //discard single pad clusters
1249 if(list[j].fTotalCharge < fThreshold) continue; //noise cluster
1252 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1253 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1254 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1255 Float_t ftime2=fZErr*fZErr; //fixed given error
1258 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1259 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1260 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1261 Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1264 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1265 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1269 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1271 fpad2*=0.108; //constants are from offline studies
1275 } else fpad2=sy2; //take the width not the error
1277 Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1280 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1281 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1285 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1287 ftime2 *= 0.169; //constants are from offline studies
1291 } else ftime2=sz2; //take the width, not the error
1295 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1298 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1299 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1301 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1302 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1303 if(fNClusters >= fMaxNClusters)
1305 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1306 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1310 fSpacePointData[counter].fX = xyz[0];
1311 // fSpacePointData[counter].fY = xyz[1];
1312 if(fCurrentSlice<18){
1313 fSpacePointData[counter].fY = xyz[1];
1316 fSpacePointData[counter].fY = -1*xyz[1];
1318 fSpacePointData[counter].fZ = xyz[2];
1321 fSpacePointData[counter].fX = fCurrentRow;
1322 fSpacePointData[counter].fY = fpad;
1323 fSpacePointData[counter].fZ = ftime;
1326 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1327 fSpacePointData[counter].fPadRow = fCurrentRow;
1328 fSpacePointData[counter].fSigmaY2 = fpad2;
1329 fSpacePointData[counter].fSigmaZ2 = ftime2;
1331 fSpacePointData[counter].fQMax = list[j].fQMax;
1333 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1334 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1336 Int_t patch=fCurrentPatch;
1337 if(patch==-1) patch=0; //never store negative patch number
1338 fSpacePointData[counter].fID = counter
1339 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1343 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1345 fSpacePointData[counter].fTrackID[0] = trackID[0];
1346 fSpacePointData[counter].fTrackID[1] = trackID[1];
1347 fSpacePointData[counter].fTrackID[2] = trackID[2];