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(),
93 fOfflineTransform = AliTPCcalibDB::Instance()->GetTransform();
94 if(!fOfflineTransform){
95 HLTError("AliHLTTPCClusterFinder(): Offline transform not in AliTPCcalibDB.");
98 fOfflineTPCRecoParam.SetUseExBCorrection(1);
99 fOfflineTPCRecoParam.SetUseTOFCorrection(1);
100 fOfflineTransform->SetCurrentRecoParam(&fOfflineTPCRecoParam);
104 AliHLTTPCClusterFinder::~AliHLTTPCClusterFinder(){
105 // see header file for class documentation
108 if(fVectorInitialized){
109 DeInitializePadArray();
111 if(fNumberOfPadsInRow){
112 delete [] fNumberOfPadsInRow;
113 fNumberOfPadsInRow=NULL;
117 void AliHLTTPCClusterFinder::InitSlice(Int_t slice,Int_t patch,Int_t nmaxpoints){
118 // see header file for class documentation
122 fMaxNClusters = nmaxpoints;
123 fCurrentSlice = slice;
124 fCurrentPatch = patch;
125 fFirstRow=AliHLTTPCTransform::GetFirstRow(patch);
126 fLastRow=AliHLTTPCTransform::GetLastRow(patch);
129 fClustersMCInfo.clear();
131 fClusterMCVector.clear();
134 void AliHLTTPCClusterFinder::InitializePadArray(){
135 // see header file for class documentation
137 if(fCurrentPatch>5||fCurrentPatch<0){
138 HLTFatal("Patch is not set");
142 HLTDebug("Patch number=%d",fCurrentPatch);
144 fFirstRow = AliHLTTPCTransform::GetFirstRow(fCurrentPatch);
145 fLastRow = AliHLTTPCTransform::GetLastRow(fCurrentPatch);
147 fNumberOfRows=fLastRow-fFirstRow+1;
148 fNumberOfPadsInRow= new UInt_t[fNumberOfRows];
150 memset( fNumberOfPadsInRow, 0, sizeof(Int_t)*(fNumberOfRows));
152 for(UInt_t i=0;i<fNumberOfRows;i++){
153 fNumberOfPadsInRow[i]=AliHLTTPCTransform::GetNPads(i+fFirstRow);
154 AliHLTTPCPadVector tmpRow;
155 for(UInt_t j=0;j<=fNumberOfPadsInRow[i];j++){
156 AliHLTTPCPad *tmpPad = new AliHLTTPCPad(2);
158 tmpRow.push_back(tmpPad);
160 fRowPadVector.push_back(tmpRow);
162 fVectorInitialized=kTRUE;
165 Int_t AliHLTTPCClusterFinder::DeInitializePadArray(){
166 // see header file for class documentation
168 for(UInt_t i=0;i<fNumberOfRows;i++){
169 for(UInt_t j=0;j<=fNumberOfPadsInRow[i];j++){
170 delete fRowPadVector[i][j];
171 fRowPadVector[i][j]=NULL;
173 fRowPadVector[i].clear();
175 fRowPadVector.clear();
181 void AliHLTTPCClusterFinder::SetOutputArray(AliHLTTPCSpacePointData *pt){
182 // see header file for class documentation
183 //set pointer to output
184 fSpacePointData = pt;
188 void AliHLTTPCClusterFinder::ReadDataUnsorted(void* ptr,unsigned long size){
189 // see header file for class documentation
191 fPtr = (UChar_t*)ptr;
194 if(!fVectorInitialized){
195 InitializePadArray();
198 if (fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice)<0) {
199 HLTError("failed setting up digit reader (InitBlock)");
203 while(fDigitReader->NextChannel()){
204 UInt_t row=fDigitReader->GetRow();
205 UInt_t pad=fDigitReader->GetPad();
207 if(row>=fRowPadVector.size()){
208 HLTError("Row number is to large: %d, max is %d",row,fRowPadVector.size()-1);
211 if(pad>=fRowPadVector[row].size()){
212 HLTError("Pad number is to large: %d, max is %d",pad,fRowPadVector[row].size());
216 while(fDigitReader->NextBunch()){
217 if(fDigitReader->GetBunchSize()>1){//to remove single timebin values, this will have to change at some point
218 UInt_t time = fDigitReader->GetTime();
219 if((Int_t)time>=fFirstTimeBin && (Int_t)time+fDigitReader->GetBunchSize()<=fLastTimeBin){
220 // Kenneth: 20-04-09. The following if have been added because of inconsistency in the 40 bit decoder and the 32 bit decoder.
221 // GetSignals() in the 40 bit decoder returns an array of UInt_t while the 32 bit one returns UShort_t
222 // The same is true for the function ReadDataUnsortedDeconvoluteTime() below.
223 // In addition the signals are organized in the opposite direction
225 const UShort_t *bunchData= fDigitReader->GetSignalsShort();
226 AliHLTTPCClusters candidate;
227 for(Int_t i=fDigitReader->GetBunchSize()-1;i>=0;i--){
228 candidate.fTotalCharge+=bunchData[i];
229 candidate.fTime += time*bunchData[i];
230 candidate.fTime2 += time*time*bunchData[i];
231 if(bunchData[i]>candidate.fQMax){
232 candidate.fQMax=bunchData[i];
236 if(candidate.fTotalCharge>0){
237 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
238 candidate.fPad=candidate.fTotalCharge*pad;
239 candidate.fPad2=candidate.fPad*pad;
240 candidate.fLastMergedPad=pad;
241 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
243 if(fRowPadVector[row][pad] != NULL){
244 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
248 const UInt_t *bunchData= fDigitReader->GetSignals();
249 AliHLTTPCClusters candidate;
250 const AliHLTTPCDigitData* digits = NULL;
251 if(fDoMC && (digits = fDigitReader->GetBunchDigits())!=NULL){
252 for(Int_t i=0;i<fDigitReader->GetBunchSize();i++){
253 candidate.fTotalCharge+=bunchData[i];
254 candidate.fTime += time*bunchData[i];
255 candidate.fTime2 += time*time*bunchData[i];
256 if(bunchData[i]>candidate.fQMax){
257 candidate.fQMax=bunchData[i];
259 fMCDigits.push_back(digits[i]);
264 for(Int_t i=0;i<fDigitReader->GetBunchSize();i++){
265 candidate.fTotalCharge+=bunchData[i];
266 candidate.fTime += time*bunchData[i];
267 candidate.fTime2 += time*time*bunchData[i];
268 if(bunchData[i]>candidate.fQMax){
269 candidate.fQMax=bunchData[i];
274 if(candidate.fTotalCharge>0){
275 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
276 candidate.fPad=candidate.fTotalCharge*pad;
277 candidate.fPad2=candidate.fPad*pad;
278 candidate.fLastMergedPad=pad;
279 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
281 if(fRowPadVector[row][pad] != NULL){
282 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
284 fRowPadVector[row][pad]->AddCandidateDigits(fMCDigits);
295 void AliHLTTPCClusterFinder::ReadDataUnsortedDeconvoluteTime(void* ptr,unsigned long size){
296 // see header file for class documentation
299 fPtr = (UChar_t*)ptr;
302 if(!fVectorInitialized){
303 InitializePadArray();
306 if (fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice)<0) {
307 HLTError("failed setting up digit reader (InitBlock)");
311 while(fDigitReader->NextChannel()){
312 UInt_t row=fDigitReader->GetRow();
313 UInt_t pad=fDigitReader->GetPad();
315 while(fDigitReader->NextBunch()){
316 if(fDigitReader->GetBunchSize()>1){//to remove single timebin values, this will have to change at some point
317 UInt_t time = fDigitReader->GetTime();
318 if((Int_t)time>=fFirstTimeBin && (Int_t)time+fDigitReader->GetBunchSize()<=fLastTimeBin){
319 Int_t indexInBunchData=0;
320 Bool_t moreDataInBunch=kFALSE;
322 Bool_t signalFalling=kFALSE;
324 // Kenneth: 20-04-09. The following if have been added because of inconsistency in the 40 bit decoder and the 32 bit decoder.
325 // GetSignals() in the 40 bit decoder returns an array of UInt_t while the 32 bit one returns UShort_t
326 // The same is true for the function ReadDataUnsorted() above.
327 // In addition the signals are organized in the opposite direction
329 indexInBunchData = fDigitReader->GetBunchSize();
330 const UShort_t *bunchData= fDigitReader->GetSignalsShort();
333 AliHLTTPCClusters candidate;
334 //for(Int_t i=indexInBunchData;i<fDigitReader->GetBunchSize();i++){
335 for(Int_t i=indexInBunchData;i>=0;i--){
336 // Checks if one need to deconvolute the signals
337 if(bunchData[i]>prevSignal && signalFalling==kTRUE){
338 if(i<fDigitReader->GetBunchSize()-1){ // means there are more than one signal left in the bunch
339 moreDataInBunch=kTRUE;
345 // Checks if the signal is 0, then quit processing the data.
346 if(bunchData[i]==0 && i<fDigitReader->GetBunchSize()-1){//means we have 0 data fom the rcu, might happen depending on the configuration settings
347 moreDataInBunch=kTRUE;
352 if(prevSignal>bunchData[i]){//means the peak of the signal has been reached and deconvolution will happen if the signal rise again.
355 candidate.fTotalCharge+=bunchData[i];
356 candidate.fTime += time*bunchData[i];
357 candidate.fTime2 += time*time*bunchData[i];
358 if(bunchData[i]>candidate.fQMax){
359 candidate.fQMax=bunchData[i];
362 prevSignal=bunchData[i];
366 if(candidate.fTotalCharge>0){
367 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
368 candidate.fPad=candidate.fTotalCharge*pad;
369 candidate.fPad2=candidate.fPad*pad;
370 candidate.fLastMergedPad=pad;
371 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
373 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
374 fRowPadVector[row][pad]->AddCandidateDigits(fMCDigits);
375 if(indexInBunchData<fDigitReader->GetBunchSize()-1){
376 moreDataInBunch=kFALSE;
378 }while(moreDataInBunch);
381 const UInt_t *bunchData= fDigitReader->GetSignals();
383 AliHLTTPCClusters candidate;
384 for(Int_t i=indexInBunchData;i<fDigitReader->GetBunchSize();i++){
385 // Checks if one need to deconvolute the signals
386 if(bunchData[i]>prevSignal && signalFalling==kTRUE){
387 if(i<fDigitReader->GetBunchSize()-1){ // means there are more than one signal left in the bunch
388 moreDataInBunch=kTRUE;
394 // Checks if the signal is 0, then quit processing the data.
395 if(bunchData[i]==0 && i<fDigitReader->GetBunchSize()-1){//means we have 0 data fom the rcu, might happen depending on the configuration settings
396 moreDataInBunch=kTRUE;
401 if(prevSignal>bunchData[i]){//means the peak of the signal has been reached and deconvolution will happen if the signal rise again.
405 candidate.fTotalCharge+=bunchData[i];
406 candidate.fTime += time*bunchData[i];
407 candidate.fTime2 += time*time*bunchData[i];
408 if(bunchData[i]>candidate.fQMax){
409 candidate.fQMax=bunchData[i];
412 prevSignal=bunchData[i];
416 if(candidate.fTotalCharge>0){
417 candidate.fMean=candidate.fTime/candidate.fTotalCharge;
418 candidate.fPad=candidate.fTotalCharge*pad;
419 candidate.fPad2=candidate.fPad*pad;
420 candidate.fLastMergedPad=pad;
421 candidate.fRowNumber=row+fDigitReader->GetRowOffset();
423 fRowPadVector[row][pad]->AddClusterCandidate(candidate);
424 if(indexInBunchData<fDigitReader->GetBunchSize()-1){
425 moreDataInBunch=kFALSE;
427 }while(moreDataInBunch);
435 Bool_t AliHLTTPCClusterFinder::ComparePads(AliHLTTPCPad *nextPad,AliHLTTPCClusters* cluster,Int_t nextPadToRead){
436 // see header file for class documentation
438 //Checking if we have a match on the next pad
439 for(UInt_t candidateNumber=0;candidateNumber<nextPad->fClusterCandidates.size();candidateNumber++){
440 if(nextPad->fUsedClusterCandidates[candidateNumber] == 1){
443 AliHLTTPCClusters *candidate =&nextPad->fClusterCandidates[candidateNumber];
444 // if(cluster->fMean-candidate->fMean==1 || candidate->fMean-cluster->fMean==1 || cluster->fMean-candidate->fMean==0){
446 if( abs((Int_t)(cluster->fMean - candidate->fMean)) <= fTimeMeanDiff ){
448 if(candidate->fTotalCharge<fTotalChargeOfPreviousClusterCandidate){//peak is reached
449 fChargeOfCandidatesFalling=kTRUE;
451 if(candidate->fTotalCharge>fTotalChargeOfPreviousClusterCandidate && fChargeOfCandidatesFalling==kTRUE){//we have deconvolution
455 cluster->fMean=candidate->fMean;
456 cluster->fTotalCharge+=candidate->fTotalCharge;
457 cluster->fTime += candidate->fTime;
458 cluster->fTime2 += candidate->fTime2;
459 cluster->fPad+=candidate->fPad;
460 cluster->fPad2+=candidate->fPad2;
461 cluster->fLastMergedPad=candidate->fPad;
462 if(candidate->fQMax>cluster->fQMax){
463 cluster->fQMax=candidate->fQMax;
466 FillMCClusterVector(nextPad->GetCandidateDigits(candidateNumber));
470 UInt_t rowNo = nextPad->GetRowNumber();
471 UInt_t padNo = nextPad->GetPadNumber();
473 fRowPadVector[rowNo][padNo-2]->fSelectedPad=kTRUE;
474 fRowPadVector[rowNo][padNo-2]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo-2);
476 fRowPadVector[rowNo][padNo-1]->fSelectedPad=kTRUE;// quick solution to set the first pad to selected
477 fRowPadVector[rowNo][padNo-1]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo-1);
478 fRowPadVector[rowNo][padNo]->fSelectedPad=kTRUE;
479 fRowPadVector[rowNo][padNo]->fHWAddress=(AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr(rowNo,padNo);
482 //setting the matched pad to used
483 nextPad->fUsedClusterCandidates[candidateNumber]=1;
485 if(nextPadToRead<(Int_t)fNumberOfPadsInRow[fRowOfFirstCandidate]){
486 nextPad=fRowPadVector[fRowOfFirstCandidate][nextPadToRead];
487 ComparePads(nextPad,cluster,nextPadToRead);
497 Int_t AliHLTTPCClusterFinder::FillHWAddressList(AliHLTUInt16_t *hwaddlist, Int_t maxHWadd){
498 // see header file for class documentation
501 for(UInt_t row=0;row<fNumberOfRows;row++){
502 for(UInt_t pad=0;pad<fNumberOfPadsInRow[row]-1;pad++){
503 if(fRowPadVector[row][pad]->fSelectedPad){
504 if(counter<maxHWadd){
505 hwaddlist[counter]=(AliHLTUInt16_t)fRowPadVector[row][pad]->fHWAddress;
509 HLTWarning("To many hardwareaddresses, skip adding");
519 Int_t AliHLTTPCClusterFinder::FillOutputMCInfo(AliHLTTPCClusterFinder::ClusterMCInfo * outputMCInfo, Int_t maxNumberOfClusterMCInfo){
520 // see header file for class documentation
524 for(UInt_t mc=0;mc<fClustersMCInfo.size();mc++){
525 if(counter<maxNumberOfClusterMCInfo){
526 outputMCInfo[counter] = fClustersMCInfo[mc];
530 HLTWarning("To much MCInfo has been added (no more space), skip adding");
536 void AliHLTTPCClusterFinder::FindClusters(){
537 // see header file for function documentation
539 AliHLTTPCClusters* tmpCandidate=NULL;
540 for(UInt_t row=0;row<fNumberOfRows;row++){
541 fRowOfFirstCandidate=row;
542 for(UInt_t pad=0;pad<fNumberOfPadsInRow[row];pad++){
543 AliHLTTPCPad *tmpPad=fRowPadVector[row][pad];
544 for(size_t candidate=0;candidate<tmpPad->fClusterCandidates.size();candidate++){
545 if(tmpPad->fUsedClusterCandidates[candidate]){
548 tmpCandidate=&tmpPad->fClusterCandidates[candidate];
549 UInt_t tmpTotalCharge=tmpCandidate->fTotalCharge;
552 fClusterMCVector.clear();
553 FillMCClusterVector(tmpPad->GetCandidateDigits(candidate));
556 ComparePads(fRowPadVector[row][pad+1],tmpCandidate,pad+1);
557 if(tmpCandidate->fTotalCharge>tmpTotalCharge){
559 fClusters.push_back(*tmpCandidate);
561 //sort the vector (large->small) according to weight and remove elements above 2 (keep 0 1 and 2)
562 sort(fClusterMCVector.begin(),fClusterMCVector.end(), MCWeight::CompareWeights );
563 ClusterMCInfo tmpClusterMCInfo;
569 if(fClusterMCVector.size()>0){
570 tmpClusterMCInfo.fClusterID[0]=fClusterMCVector.at(0);
573 tmpClusterMCInfo.fClusterID[0]=zeroMC;
576 if(fClusterMCVector.size()>1){
577 tmpClusterMCInfo.fClusterID[1]=fClusterMCVector.at(1);
580 tmpClusterMCInfo.fClusterID[1]=zeroMC;
583 if(fClusterMCVector.size()>2){
584 tmpClusterMCInfo.fClusterID[2]=fClusterMCVector.at(2);
587 tmpClusterMCInfo.fClusterID[2]=zeroMC;
590 fClustersMCInfo.push_back(tmpClusterMCInfo);
595 tmpPad->ClearCandidates();
597 fRowPadVector[row][fNumberOfPadsInRow[row]]->ClearCandidates();
600 HLTInfo("Found %d clusters.",fClusters.size());
602 //TODO: Change so it stores AliHLTTPCSpacePointData directly, instead of this copying
604 AliClusterData * clusterlist = new AliClusterData[fClusters.size()]; //Clusterlist
605 for(unsigned int i=0;i<fClusters.size();i++){
606 clusterlist[i].fTotalCharge = fClusters[i].fTotalCharge;
607 clusterlist[i].fPad = fClusters[i].fPad;
608 clusterlist[i].fPad2 = fClusters[i].fPad2;
609 clusterlist[i].fTime = fClusters[i].fTime;
610 clusterlist[i].fTime2 = fClusters[i].fTime2;
611 clusterlist[i].fMean = fClusters[i].fMean;
612 clusterlist[i].fFlags = fClusters[i].fFlags;
613 clusterlist[i].fChargeFalling = fClusters[i].fChargeFalling;
614 clusterlist[i].fLastCharge = fClusters[i].fLastCharge;
615 clusterlist[i].fLastMergedPad = fClusters[i].fLastMergedPad;
616 clusterlist[i].fRow = fClusters[i].fRowNumber;
617 clusterlist[i].fQMax = fClusters[i].fQMax;
620 WriteClusters(fClusters.size(),clusterlist);
621 delete [] clusterlist;
626 Bool_t AliHLTTPCClusterFinder::UpdateCalibDB(){
629 AliTPCcalibDB::Instance()->Update();
631 //uptate the transform class
632 AliTPCTransform * tmp = AliTPCcalibDB::Instance()->GetTransform();
634 HLTError("AliHLTTPCClusterFinder::UpdateCAlibDB: Offline transform not in AliTPCcalibDB.");
637 fOfflineTransform = tmp;
641 //---------------------------------- Under this line the old sorted clusterfinder functions can be found --------------------------------
644 void AliHLTTPCClusterFinder::PrintClusters(){
645 // see header file for class documentation
647 for(size_t i=0;i<fClusters.size();i++){
648 HLTInfo("Cluster number: %d",i);
649 HLTInfo("Row: %d \t Pad: %d",fClusters[i].fRowNumber,fClusters[i].fPad/fClusters[i].fTotalCharge);
650 HLTInfo("Total Charge: %d",fClusters[i].fTotalCharge);
651 HLTInfo("fPad: %d",fClusters[i].fPad);
652 HLTInfo("PadError: %d",fClusters[i].fPad2);
653 HLTInfo("TimeMean: %d",fClusters[i].fTime/fClusters[i].fTotalCharge);
654 HLTInfo("TimeError: %d",fClusters[i].fTime2);
655 HLTInfo("EndOfCluster:");
659 void AliHLTTPCClusterFinder::FillMCClusterVector(vector<AliHLTTPCDigitData> digitData){
661 for(UInt_t d=0;d<digitData.size();d++){
662 Int_t nIDsInDigit = (digitData.at(d).fTrackID[0]>=0) + (digitData.at(d).fTrackID[1]>=0) + (digitData.at(d).fTrackID[2]>=0);
663 for(Int_t id=0; id<3; id++){
664 if(digitData.at(d).fTrackID[id]>=0){
665 Bool_t matchFound = kFALSE;
667 mc.fMCID = digitData.at(d).fTrackID[id];
668 mc.fWeight = ((Float_t)digitData.at(d).fCharge)/nIDsInDigit;
669 for(UInt_t i=0;i<fClusterMCVector.size();i++){
670 if(mc.fMCID == fClusterMCVector.at(i).fMCID){
671 fClusterMCVector.at(i).fWeight += mc.fWeight;
675 if(matchFound == kFALSE){
676 fClusterMCVector.push_back(mc);
684 void AliHLTTPCClusterFinder::Read(void* ptr,unsigned long size){
686 fPtr = (UChar_t*)ptr;
690 void AliHLTTPCClusterFinder::ProcessDigits(){
691 // see header file for class documentation
694 bool readValue = true;
697 UShort_t time=0,newTime=0;
698 UInt_t pad=0,newPad=0;
699 AliHLTTPCSignal_t charge=0;
703 // initialize block for reading packed data
704 iResult=fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice);
705 if (iResult<0) return;
707 readValue = fDigitReader->Next();
709 // Matthias 08.11.2006 the following return would cause termination without writing the
710 // ClusterData and thus would block the component. I just want to have the commented line
711 // here for information
712 //if (!readValue)return;
714 pad = fDigitReader->GetPad();
715 time = fDigitReader->GetTime();
716 fCurrentRow = fDigitReader->GetRow();
718 if ( fCurrentPatch >= 2 ) // Outer sector, patches 2, 3, 4, 5
719 rowOffset = AliHLTTPCTransform::GetFirstRow( 2 );
721 fCurrentRow += rowOffset;
723 UInt_t lastpad = 123456789;
724 const UInt_t kPadArraySize=5000;
725 const UInt_t kClusterListSize=10000;
726 AliClusterData *pad1[kPadArraySize]; //2 lists for internal memory=2pads
727 AliClusterData *pad2[kPadArraySize]; //2 lists for internal memory=2pads
728 AliClusterData clusterlist[kClusterListSize]; //Clusterlist
730 AliClusterData **currentPt; //List of pointers to the current pad
731 AliClusterData **previousPt; //List of pointers to the previous pad
734 UInt_t nprevious=0,ncurrent=0,ntotal=0;
736 /* quick implementation of baseline calculation and zero suppression
737 open a pad object for each pad and delete it after processing.
738 later a list of pad objects with base line history can be used
739 The whole thing only works if we really get unprocessed raw data, if
740 the data is already zero suppressed, there might be gaps in the time
743 Int_t gatingGridOffset=50;
745 gatingGridOffset=fFirstTimeBin;
747 AliHLTTPCPad baseline(gatingGridOffset, AliHLTTPCTransform::GetNTimeBins());
748 // just to make later conversion to a list of objects easier
749 AliHLTTPCPad* pCurrentPad=NULL;
751 if (fSignalThreshold>=0) {
752 pCurrentPad=&baseline;
753 baseline.SetThreshold(fSignalThreshold);
756 while ( readValue!=0 && iResult>=0){ // Reads through all digits in block
763 if(currentPt == pad2){
771 nprevious = ncurrent;
773 if(pad != lastpad+1){
774 //this happens if there is a pad with no signal.
775 nprevious = ncurrent = 0;
780 Bool_t newcluster = kTRUE;
781 UInt_t seqcharge=0,seqaverage=0,seqerror=0;
782 AliHLTTPCSignal_t lastcharge=0;
783 UInt_t bLastWasFalling=0;
788 redo: //This is a goto.
799 while(iResult>=0){ //Loop over time bins of current pad
800 // read all the values for one pad at once to calculate the base line
802 if (!pCurrentPad->IsStarted()) {
803 //HLTDebug("reading data for pad %d, padrow %d", fDigitReader->GetPad(), fDigitReader->GetRow()+rowOffset);
804 pCurrentPad->SetID(fDigitReader->GetRow()+rowOffset,fDigitReader->GetPad());
805 if ((pCurrentPad->StartEvent())>=0) {
807 if ((fDigitReader->GetRow()+rowOffset)!=pCurrentPad->GetRowNumber()) break;
808 if (fDigitReader->GetPad()!=pCurrentPad->GetPadNumber()) break;
809 pCurrentPad->SetRawData(fDigitReader->GetTime(), fDigitReader->GetSignal());
810 //HLTDebug("set raw data to pad: bin %d charge %d", fDigitReader->GetTime(), fDigitReader->GetSignal());
811 } while ((readValue = fDigitReader->Next())!=0);
813 pCurrentPad->CalculateBaseLine(AliHLTTPCTransform::GetNTimeBins()/2);
814 if (pCurrentPad->Next(kTRUE/*do zero suppression*/)==0) {
815 //HLTDebug("no data available after zero suppression");
816 pCurrentPad->StopEvent();
817 pCurrentPad->ResetHistory();
820 time=pCurrentPad->GetCurrentPosition();
821 if (time>pCurrentPad->GetSize()) {
822 HLTError("invalid time bin for pad");
828 Float_t occupancy=pCurrentPad->GetOccupancy();
829 //HLTDebug("pad %d occupancy level: %f", pCurrentPad->GetPadNumber(), occupancy);
830 if ( occupancy < fOccupancyLimit ) {
831 charge = pCurrentPad->GetCorrectedData();
834 //HLTDebug("ignoring pad %d with occupancy level %f", pCurrentPad->GetPadNumber(), occupancy);
837 charge = fDigitReader->GetSignal();
839 //HLTDebug("get next charge value: position %d charge %d", time, charge);
843 if (fDigitReader->GetRow() == 90){
844 ///// LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::Row","row90") << "PAD=" << fDigitReader->GetPad() << " TIME=" << fDigitReader->GetTime()
845 // << " SIGNAL=" << fDigitReader->GetSignal() << ENDLOG;
849 if(time >= AliHLTTPCTransform::GetNTimeBins()){
850 HLTWarning("Pad %d: Timebin (%d) out of range (%d)", pad, time, AliHLTTPCTransform::GetNTimeBins());
855 //Get the current ADC-value
858 //Check if the last pixel in the sequence is smaller than this
859 if(charge > lastcharge){
865 else bLastWasFalling = 1; //last pixel was larger than this
869 //Sum the total charge of this sequence
871 seqaverage += time*charge;
872 seqerror += time*time*charge;
876 if((pCurrentPad->Next(kTRUE/*do zero suppression*/))==0) {
877 pCurrentPad->StopEvent();
878 pCurrentPad->ResetHistory();
880 newPad = fDigitReader->GetPad();
881 newTime = fDigitReader->GetTime();
882 newRow = fDigitReader->GetRow() + rowOffset;
887 newPad=pCurrentPad->GetPadNumber();
888 newTime=pCurrentPad->GetCurrentPosition();
889 newRow=pCurrentPad->GetRowNumber();
891 readValue = fDigitReader->Next();
892 //Check where to stop:
893 if(!readValue) break; //No more value
895 newPad = fDigitReader->GetPad();
896 newTime = fDigitReader->GetTime();
897 newRow = fDigitReader->GetRow() + rowOffset;
900 if(newPad != pad)break; //new pad
901 if(newTime != time+1) break; //end of sequence
904 // pad = newpad; is equal
907 }//end loop over sequence
909 //HLTDebug("ended time bin sequence loop: seqcharge=%d readValue=%d", seqcharge, readValue);
910 //HLTDebug("pad=%d newpad=%d current row=%d newrow=%d", pad, newPad, fCurrentRow, newRow);
912 // with active zero suppression zero values are possible
916 //Calculate mean of sequence:
919 seqmean = seqaverage/seqcharge;
921 LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::ProcessRow","Data")
922 <<"Error in data given to the cluster finder"<<ENDLOG;
927 //Calculate mean in pad direction:
928 Int_t padmean = seqcharge*pad;
929 Int_t paderror = pad*padmean;
931 //Compare with results on previous pad:
932 for(UInt_t p=0; p<nprevious && p<kPadArraySize && ncurrent<kPadArraySize; p++){
934 //dont merge sequences on the same pad twice
935 if(previousPt[p]->fLastMergedPad==pad) continue;
937 Int_t difference = seqmean - previousPt[p]->fMean;
938 if(difference < -fMatch) break;
940 if(difference <= fMatch){ //There is a match here!!
941 AliClusterData *local = previousPt[p];
944 if(seqcharge > local->fLastCharge){
945 if(local->fChargeFalling){ //The previous pad was falling
946 break; //create a new cluster
949 else local->fChargeFalling = 1;
950 local->fLastCharge = seqcharge;
953 //Don't create a new cluster, because we found a match
956 //Update cluster on current pad with the matching one:
957 local->fTotalCharge += seqcharge;
958 local->fPad += padmean;
959 local->fPad2 += paderror;
960 local->fTime += seqaverage;
961 local->fTime2 += seqerror;
962 local->fMean = seqmean;
963 local->fFlags++; //means we have more than one pad
964 local->fLastMergedPad = pad;
966 currentPt[ncurrent] = local;
970 } //Checking for match at previous pad
971 } //Loop over results on previous pad.
973 if(newcluster && ncurrent<kPadArraySize){
974 //Start a new cluster. Add it to the clusterlist, and update
975 //the list of pointers to clusters in current pad.
976 //current pad will be previous pad on next pad.
978 //Add to the clusterlist:
979 AliClusterData *tmp = &clusterlist[ntotal];
980 tmp->fTotalCharge = seqcharge;
982 tmp->fPad2 = paderror;
983 tmp->fTime = seqaverage;
984 tmp->fTime2 = seqerror;
985 tmp->fMean = seqmean;
986 tmp->fFlags = 0; //flags for single pad clusters
987 tmp->fLastMergedPad = pad;
990 tmp->fChargeFalling = 0;
991 tmp->fLastCharge = seqcharge;
994 //Update list of pointers to previous pad:
995 currentPt[ncurrent] = &clusterlist[ntotal];
1001 if(newbin >= 0) goto redo;
1003 // to prevent endless loop
1004 if(time >= AliHLTTPCTransform::GetNTimeBins()){
1005 HLTWarning("Timebin (%d) out of range (%d)", time, AliHLTTPCTransform::GetNTimeBins());
1010 if(!readValue) break; //No more value
1012 if (ntotal>=kClusterListSize || ncurrent>=kPadArraySize) {
1013 HLTWarning("pad array size exceeded ntotal=%d ncurrent=%d, skip rest of the data", ntotal, ncurrent);
1017 if(fCurrentRow != newRow){
1018 WriteClusters(ntotal,clusterlist);
1020 lastpad = 123456789;
1028 fCurrentRow = newRow;
1034 } // END while(readValue)
1036 WriteClusters(ntotal,clusterlist);
1038 HLTInfo("ClusterFinder found %d clusters in slice %d patch %d", fNClusters, fCurrentSlice, fCurrentPatch);
1042 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliClusterData *list){
1043 // see header file for class documentation
1045 //write cluster to output pointer
1046 Int_t thisrow=-1,thissector=-1;
1047 UInt_t counter = fNClusters;
1049 for(int j=0; j<nclusters; j++)
1054 if(!list[j].fFlags){
1056 if(j+(Int_t)fClustersMCInfo.size()-nclusters >=0 && j+fClustersMCInfo.size()-nclusters < fClustersMCInfo.size()){
1057 fClustersMCInfo.erase(fClustersMCInfo.begin()+j+fClustersMCInfo.size()-nclusters); // remove the mc info for this cluster since it is not taken into account
1060 continue; //discard single pad clusters
1062 if(list[j].fTotalCharge < fThreshold){
1064 if(j+(Int_t)fClustersMCInfo.size()-nclusters >=0 && j+fClustersMCInfo.size()-nclusters < fClustersMCInfo.size()){
1065 fClustersMCInfo.erase(fClustersMCInfo.begin()+j+fClustersMCInfo.size()-nclusters); // remove the mc info for this cluster since it is not taken into account
1068 continue; //noise cluster
1071 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1072 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1073 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1074 Float_t ftime2=fZErr*fZErr; //fixed given error
1079 fCurrentRow=list[j].fRow;
1083 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1084 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1085 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1086 // Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1087 Float_t sy2=(Float_t)list[j].fPad2 * list[j].fTotalCharge - (Float_t)list[j].fPad * list[j].fPad;
1090 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1091 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1095 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1097 fpad2*=0.108; //constants are from offline studies
1101 } else fpad2=sy2; //take the width not the error
1103 // Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1104 Float_t sz2=(Float_t)list[j].fTime2*list[j].fTotalCharge - (Float_t)list[j].fTime*list[j].fTime;
1107 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1108 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1112 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1114 ftime2 *= 0.169; //constants are from offline studies
1118 } else ftime2=sz2; //take the width, not the error
1122 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1125 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1127 if(fOfflineTransform == NULL){
1128 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1130 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1131 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1132 if(fNClusters >= fMaxNClusters)
1134 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1135 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1139 fSpacePointData[counter].fX = xyz[0];
1140 // fSpacePointData[counter].fY = xyz[1];
1141 if(fCurrentSlice<18){
1142 fSpacePointData[counter].fY = xyz[1];
1145 fSpacePointData[counter].fY = -1*xyz[1];
1147 fSpacePointData[counter].fZ = xyz[2];
1150 Double_t x[3]={thisrow,fpad+.5,ftime};
1151 Int_t iSector[1]={thissector};
1152 fOfflineTransform->Transform(x,iSector,0,1);
1153 fSpacePointData[counter].fX = x[0];
1154 fSpacePointData[counter].fY = x[1];
1155 fSpacePointData[counter].fZ = x[2];
1160 fSpacePointData[counter].fX = fCurrentRow;
1161 fSpacePointData[counter].fY = fpad;
1162 fSpacePointData[counter].fZ = ftime;
1165 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1166 fSpacePointData[counter].fPadRow = fCurrentRow;
1167 fSpacePointData[counter].fSigmaY2 = fpad2;
1168 fSpacePointData[counter].fSigmaZ2 = ftime2;
1170 fSpacePointData[counter].fQMax = list[j].fQMax;
1172 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1173 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1175 Int_t patch=fCurrentPatch;
1176 if(patch==-1) patch=0; //never store negative patch number
1177 fSpacePointData[counter].fID = counter
1178 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1182 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1184 fSpacePointData[counter].fTrackID[0] = trackID[0];
1185 fSpacePointData[counter].fTrackID[1] = trackID[1];
1186 fSpacePointData[counter].fTrackID[2] = trackID[2];
1195 // STILL TO FIX ----------------------------------------------------------------------------
1198 void AliHLTTPCClusterFinder::GetTrackID(Int_t pad,Int_t time,Int_t *trackID){
1199 // see header file for class documentation
1202 AliHLTTPCDigitRowData *rowPt = (AliHLTTPCDigitRowData*)fDigitRowData;
1204 trackID[0]=trackID[1]=trackID[2]=-2;
1205 for(Int_t i=fFirstRow; i<=fLastRow; i++){
1206 if(rowPt->fRow < (UInt_t)fCurrentRow){
1207 AliHLTTPCMemHandler::UpdateRowPointer(rowPt);
1210 AliHLTTPCDigitData *digPt = (AliHLTTPCDigitData*)rowPt->fDigitData;
1211 for(UInt_t j=0; j<rowPt->fNDigit; j++){
1212 Int_t cpad = digPt[j].fPad;
1213 Int_t ctime = digPt[j].fTime;
1214 if(cpad != pad) continue;
1215 if(ctime != time) continue;
1217 trackID[0] = digPt[j].fTrackID[0];
1218 trackID[1] = digPt[j].fTrackID[1];
1219 trackID[2] = digPt[j].fTrackID[2];
1230 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliHLTTPCClusters *list){//This is used when using the AliHLTTPCClusters class for cluster data
1231 // see header file for class documentation
1233 //write cluster to output pointer
1234 Int_t thisrow,thissector;
1235 UInt_t counter = fNClusters;
1237 for(int j=0; j<nclusters; j++)
1239 if(!list[j].fFlags) continue; //discard single pad clusters
1240 if(list[j].fTotalCharge < fThreshold) continue; //noise cluster
1243 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
1244 Float_t fpad2=fXYErr*fXYErr; //fixed given error
1245 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
1246 Float_t ftime2=fZErr*fZErr; //fixed given error
1249 if(fCalcerr) { //calc the errors, otherwice take the fixed error
1250 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
1251 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
1252 Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
1255 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1256 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1260 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
1262 fpad2*=0.108; //constants are from offline studies
1266 } else fpad2=sy2; //take the width not the error
1268 Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
1271 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
1272 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
1276 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
1278 ftime2 *= 0.169; //constants are from offline studies
1282 } else ftime2=sz2; //take the width, not the error
1286 HLTInfo("WriteCluster: padrow %d pad %d +- %d time +- %d charge %d",fCurrentRow, fpad, fpad2, ftime, ftime2, list[j].fTotalCharge);
1289 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
1290 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
1292 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
1293 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
1294 if(fNClusters >= fMaxNClusters)
1296 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
1297 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
1301 fSpacePointData[counter].fX = xyz[0];
1302 // fSpacePointData[counter].fY = xyz[1];
1303 if(fCurrentSlice<18){
1304 fSpacePointData[counter].fY = xyz[1];
1307 fSpacePointData[counter].fY = -1*xyz[1];
1309 fSpacePointData[counter].fZ = xyz[2];
1312 fSpacePointData[counter].fX = fCurrentRow;
1313 fSpacePointData[counter].fY = fpad;
1314 fSpacePointData[counter].fZ = ftime;
1317 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
1318 fSpacePointData[counter].fPadRow = fCurrentRow;
1319 fSpacePointData[counter].fSigmaY2 = fpad2;
1320 fSpacePointData[counter].fSigmaZ2 = ftime2;
1322 fSpacePointData[counter].fQMax = list[j].fQMax;
1324 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
1325 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
1327 Int_t patch=fCurrentPatch;
1328 if(patch==-1) patch=0; //never store negative patch number
1329 fSpacePointData[counter].fID = counter
1330 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
1334 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
1336 fSpacePointData[counter].fTrackID[0] = trackID[0];
1337 fSpacePointData[counter].fTrackID[1] = trackID[1];
1338 fSpacePointData[counter].fTrackID[2] = trackID[2];