2 // Original: AliHLTClustFinderNew.cxx,v 1.29 2005/06/14 10:55:21 cvetan Exp
4 /**************************************************************************
5 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
7 * Authors: Anders Vestbo <mailto:vestbo@fi.uib.no>, *
8 * Constantin Loizides <mailto:loizides@ikf.uni-frankfurt.de> *
9 * Jochen Thaeder <mailto:thaeder@kip.uni-heidelberg.de> *
10 * for The ALICE Off-line Project. *
12 * Permission to use, copy, modify and distribute this software and its *
13 * documentation strictly for non-commercial purposes is hereby granted *
14 * without fee, provided that the above copyright notice appears in all *
15 * copies and that both the copyright notice and this permission notice *
16 * appear in the supporting documentation. The authors make no claims *
17 * about the suitability of this software for any purpose. It is *
18 * provided "as is" without express or implied warranty. *
19 **************************************************************************/
21 /** @file AliHLTTPCClusterFinder.cxx
22 @author Anders Vestbo <mailto:vestbo@fi.uib.no>,
23 Constantin Loizides <mailto:loizides@ikf.uni-frankfurt.de>
24 Jochen Thaeder <mailto:thaeder@kip.uni-heidelberg.de>
26 @brief Cluster Finder for the TPC
29 #include "AliHLTTPCDigitReader.h"
30 #include "AliHLTTPCRootTypes.h"
31 #include "AliHLTTPCLogging.h"
32 #include "AliHLTTPCClusterFinder.h"
33 #include "AliHLTTPCDigitData.h"
34 #include "AliHLTTPCTransform.h"
35 #include "AliHLTTPCSpacePointData.h"
36 #include "AliHLTTPCMemHandler.h"
37 #include "AliHLTTPCPad.h"
43 /** \class AliHLTTPCClusterFinder
45 // The current cluster finder for HLT
48 // The cluster finder is initialized with the Init function,
49 // providing the slice and patch information to work on.
51 // The input is a provided by the AliHLTTPCDigitReader class,
52 // using the init() funktion, and the next() funktion in order
53 // to get the next bin. Either packed or unpacked data can be
54 // processed, dependent if one uses AliHLTTPCDigitReaderPacked
55 // class or AliHLTTPCDigitReaderUnpacked class in the
56 // Clusterfinder Component.
57 // The resulting space points will be in the
58 // array given by the SetOutputArray function.
60 // There are several setters which control the behaviour:
62 // - SetXYError(Float_t): set fixed error in XY direction
63 // - SetZError(Float_t): set fixed error in Z direction
64 // (used if errors are not calculated)
65 // - SetDeconv(Bool_t): switch on/off deconvolution
66 // - SetThreshold(UInt_t): set charge threshold for cluster
67 // - SetMatchWidth(UInt_t): set the match distance in
68 // time for sequences to be merged
69 // - SetSTDOutput(Bool_t): switch on/off output about found clusters
70 // - SetCalcErr(Bool_t): switch on/off calculation of
71 // space point errors (or widths in raw system)
72 // - SetRawSP(Bool_t): switch on/off convertion to raw system
77 // AliHLTTPCFileHandler *file = new AliHLTTPCFileHandler();
78 // file->SetAliInput(digitfile); //give some input file
79 // for(int slice=0; slice<=35; slice++){
80 // for(int patch=0; pat<6; pat++){
81 // file->Init(slice,patch);
83 // UInt_t maxclusters=100000;
84 // UInt_t pointsize = maxclusters*sizeof(AliHLTTPCSpacePointData);
85 // AliHLTTPCSpacePointData *points = (AliHLTTPCSpacePointData*)memory->Allocate(pointsize);
86 // AliHLTTPCDigitRowData *digits = (AliHLTTPCDigitRowData*)file->AliAltroDigits2Memory(ndigits,event);
87 // AliHLTTPCClusterFinder *cf = new AliHLTTPCClusterFinder();
88 // cf->SetMatchWidth(2);
89 // cf->InitSlice( slice, patch, row[0], row[1], maxPoints );
90 // cf->SetSTDOutput(kTRUE); //Some output to standard IO
91 // cf->SetRawSP(kFALSE); //Convert space points to local system
92 // cf->SetThreshold(5); //Threshold of cluster charge
93 // cf->SetDeconv(kTRUE); //Deconv in pad and time direction
94 // cf->SetCalcErr(kTRUE); //Calculate the errors of the spacepoints
95 // cf->SetOutputArray(points); //Move the spacepoints to the array
96 // cf->Read(iter->fPtr, iter->fSize ); //give the data to the cf
97 // cf->ProcessDigits(); //process the rows given by init
98 // Int_t npoints = cf->GetNumberOfClusters();
99 // AliHLTTPCMemHandler *out= new AliHLTTPCMemHandler();
100 // out->SetBinaryOutput(fname);
101 // out->Memory2Binary(npoints,points); //store the spacepoints
102 // out->CloseBinaryOutput();
110 ClassImp(AliHLTTPCClusterFinder)
112 AliHLTTPCClusterFinder::AliHLTTPCClusterFinder()
114 fSpacePointData(NULL),
130 fSignalThreshold(-1),
140 AliHLTTPCClusterFinder::AliHLTTPCClusterFinder(const AliHLTTPCClusterFinder& src)
142 fSpacePointData(NULL),
143 fDigitReader(src.fDigitReader),
146 fDeconvTime(src.fDeconvTime),
147 fDeconvPad(src.fDeconvPad),
148 fStdout(src.fStdout),
149 fCalcerr(src.fCalcerr),
151 fFirstRow(src.fFirstRow),
152 fLastRow(src.fLastRow),
153 fCurrentRow(src.fCurrentRow),
154 fCurrentSlice(src.fCurrentSlice),
155 fCurrentPatch(src.fCurrentPatch),
157 fThreshold(src.fThreshold),
158 fSignalThreshold(src.fSignalThreshold),
159 fNClusters(src.fNClusters),
160 fMaxNClusters(src.fMaxNClusters),
163 fOccupancyLimit(src.fOccupancyLimit)
167 AliHLTTPCClusterFinder& AliHLTTPCClusterFinder::operator=(const AliHLTTPCClusterFinder& src)
170 fThreshold=src.fThreshold;
171 fSignalThreshold=src.fSignalThreshold;
172 fOccupancyLimit=src.fOccupancyLimit;
175 fDeconvPad=src.fDeconvPad;
176 fDeconvTime=src.fDeconvTime;
178 fCalcerr=src.fCalcerr;
180 fFirstRow=src.fFirstRow;
181 fLastRow=src.fLastRow;
182 fDigitReader=src.fDigitReader;
186 AliHLTTPCClusterFinder::~AliHLTTPCClusterFinder()
191 void AliHLTTPCClusterFinder::InitSlice(Int_t slice,Int_t patch,Int_t firstrow, Int_t lastrow,Int_t nmaxpoints)
195 fMaxNClusters = nmaxpoints;
196 fCurrentSlice = slice;
197 fCurrentPatch = patch;
198 fFirstRow = firstrow;
202 void AliHLTTPCClusterFinder::InitSlice(Int_t slice,Int_t patch,Int_t nmaxpoints)
206 fMaxNClusters = nmaxpoints;
207 fCurrentSlice = slice;
208 fCurrentPatch = patch;
209 fFirstRow=AliHLTTPCTransform::GetFirstRow(patch);
210 fLastRow=AliHLTTPCTransform::GetLastRow(patch);
213 void AliHLTTPCClusterFinder::SetOutputArray(AliHLTTPCSpacePointData *pt)
215 //set pointer to output
216 fSpacePointData = pt;
219 void AliHLTTPCClusterFinder::Read(void* ptr,unsigned long size){
221 fPtr = (UChar_t*)ptr;
225 void AliHLTTPCClusterFinder::ProcessDigits()
227 bool readValue = true;
230 UShort_t time=0,newTime=0;
231 UInt_t pad=0,newPad=0;
232 AliHLTTPCSignal_t charge=0;
236 // initialize block for reading packed data
237 fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice);
238 readValue = fDigitReader->Next();
240 // Matthias 08.11.2006 the following return would cause termination without writing the
241 // ClusterData and thus would block the component. I just want to have the commented line
242 // here for information
243 //if (!readValue)return;
245 pad = fDigitReader->GetPad();
246 time = fDigitReader->GetTime();
247 fCurrentRow = fDigitReader->GetRow();
249 if ( fCurrentPatch >= 2 ) // Outer sector, patches 2, 3, 4, 5
250 rowOffset = AliHLTTPCTransform::GetFirstRow( 2 );
252 fCurrentRow += rowOffset;
254 UInt_t lastpad = 123456789;
255 const UInt_t kPadArraySize=5000;
256 const UInt_t kClusterListSize=10000;
257 AliClusterData *pad1[kPadArraySize]; //2 lists for internal memory=2pads
258 AliClusterData *pad2[kPadArraySize]; //2 lists for internal memory=2pads
259 AliClusterData clusterlist[kClusterListSize]; //Clusterlist
261 AliClusterData **currentPt; //List of pointers to the current pad
262 AliClusterData **previousPt; //List of pointers to the previous pad
265 UInt_t nprevious=0,ncurrent=0,ntotal=0;
267 /* quick implementation of baseline calculation and zero suppression
268 open a pad object for each pad and delete it after processing.
269 later a list of pad objects with base line history can be used
270 The whole thing only works if we really get unprocessed raw data, if
271 the data is already zero suppressed, there might be gaps in the time
274 Int_t gatingGridOffset=50;
275 AliHLTTPCPad baseline(gatingGridOffset, AliHLTTPCTransform::GetNTimeBins());
276 // just to make later conversion to a list of objects easier
277 AliHLTTPCPad* pCurrentPad=NULL;
278 if (fSignalThreshold>=0) {
279 pCurrentPad=&baseline;
280 baseline.SetThreshold(fSignalThreshold);
283 while ( readValue ){ // Reads through all digits in block
289 if(currentPt == pad2){
297 nprevious = ncurrent;
299 if(pad != lastpad+1){
300 //this happens if there is a pad with no signal.
301 nprevious = ncurrent = 0;
306 Bool_t newcluster = kTRUE;
307 UInt_t seqcharge=0,seqaverage=0,seqerror=0;
308 AliHLTTPCSignal_t lastcharge=0;
309 UInt_t bLastWasFalling=0;
314 redo: //This is a goto.
325 while(1){ //Loop over time bins of current pad
326 // read all the values for one pad at once to calculate the base line
328 if (!pCurrentPad->IsStarted()) {
329 //HLTDebug("reading data for pad %d, padrow %d", fDigitReader->GetPad(), fDigitReader->GetRow()+rowOffset);
330 pCurrentPad->SetID(fDigitReader->GetRow()+rowOffset,fDigitReader->GetPad());
331 if ((pCurrentPad->StartEvent())>=0) {
333 if ((fDigitReader->GetRow()+rowOffset)!=pCurrentPad->GetRowNumber()) break;
334 if (fDigitReader->GetPad()!=pCurrentPad->GetPadNumber()) break;
335 pCurrentPad->SetRawData(fDigitReader->GetTime(), fDigitReader->GetSignal());
336 //HLTDebug("set raw data to pad: bin %d charge %d", fDigitReader->GetTime(), fDigitReader->GetSignal());
337 } while ((readValue = fDigitReader->Next())!=0);
339 pCurrentPad->CalculateBaseLine(AliHLTTPCTransform::GetNTimeBins()/2);
340 if (pCurrentPad->Next(kTRUE/*do zero suppression*/)==0) {
341 //HLTDebug("no data available after zero suppression");
342 pCurrentPad->StopEvent();
343 pCurrentPad->ResetHistory();
346 time=pCurrentPad->GetCurrentPosition();
347 if (time>pCurrentPad->GetSize()) {
348 HLTError("invalid time bin for pad");
355 Float_t occupancy=pCurrentPad->GetOccupancy();
356 //HLTDebug("pad %d occupancy level: %f", pCurrentPad->GetPadNumber(), occupancy);
357 if ( occupancy < fOccupancyLimit ) {
358 charge = pCurrentPad->GetCorrectedData();
361 //HLTDebug("ignoring pad %d with occupancy level %f", pCurrentPad->GetPadNumber(), occupancy);
364 charge = fDigitReader->GetSignal();
366 //HLTDebug("get next charge value: position %d charge %d", time, charge);
370 if (fDigitReader->GetRow() == 90){
371 ///// LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::Row","row90") << "PAD=" << fDigitReader->GetPad() << " TIME=" << fDigitReader->GetTime()
372 // << " SIGNAL=" << fDigitReader->GetSignal() << ENDLOG;
376 if(time >= AliHLTTPCTransform::GetNTimeBins()){
377 HLTWarning("Timebin (%d) out of range (%d)", time, AliHLTTPCTransform::GetNTimeBins());
382 //Get the current ADC-value
385 //Check if the last pixel in the sequence is smaller than this
386 if(charge > lastcharge){
392 else bLastWasFalling = 1; //last pixel was larger than this
396 //Sum the total charge of this sequence
398 seqaverage += time*charge;
399 seqerror += time*time*charge;
403 if((pCurrentPad->Next(kTRUE/*do zero suppression*/))==0) {
404 pCurrentPad->StopEvent();
405 pCurrentPad->ResetHistory();
407 newPad = fDigitReader->GetPad();
408 newTime = fDigitReader->GetTime();
409 newRow = fDigitReader->GetRow() + rowOffset;
414 newPad=pCurrentPad->GetPadNumber();
415 newTime=pCurrentPad->GetCurrentPosition();
416 newRow=pCurrentPad->GetRowNumber();
418 readValue = fDigitReader->Next();
419 //Check where to stop:
420 if(!readValue) break; //No more value
422 newPad = fDigitReader->GetPad();
423 newTime = fDigitReader->GetTime();
424 newRow = fDigitReader->GetRow() + rowOffset;
427 if(newPad != pad)break; //new pad
428 if(newTime != time+1) break; //end of sequence
430 // pad = newpad; is equal
433 }//end loop over sequence
435 //HLTDebug("ended time bin sequence loop: seqcharge=%d readValue=%d", seqcharge, readValue);
436 //HLTDebug("pad=%d newpad=%d current row=%d newrow=%d", pad, newPad, fCurrentRow, newRow);
438 // with active zero suppression zero values are possible
442 //Calculate mean of sequence:
445 seqmean = seqaverage/seqcharge;
447 LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::ProcessRow","Data")
448 <<"Error in data given to the cluster finder"<<ENDLOG;
453 //Calculate mean in pad direction:
454 Int_t padmean = seqcharge*pad;
455 Int_t paderror = pad*padmean;
457 //Compare with results on previous pad:
458 for(UInt_t p=0; p<nprevious && p<kPadArraySize && ncurrent<kPadArraySize; p++){
460 //dont merge sequences on the same pad twice
461 if(previousPt[p]->fLastMergedPad==pad) continue;
463 Int_t difference = seqmean - previousPt[p]->fMean;
464 if(difference < -fMatch) break;
466 if(difference <= fMatch){ //There is a match here!!
467 AliClusterData *local = previousPt[p];
470 if(seqcharge > local->fLastCharge){
471 if(local->fChargeFalling){ //The previous pad was falling
472 break; //create a new cluster
475 else local->fChargeFalling = 1;
476 local->fLastCharge = seqcharge;
479 //Don't create a new cluster, because we found a match
482 //Update cluster on current pad with the matching one:
483 local->fTotalCharge += seqcharge;
484 local->fPad += padmean;
485 local->fPad2 += paderror;
486 local->fTime += seqaverage;
487 local->fTime2 += seqerror;
488 local->fMean = seqmean;
489 local->fFlags++; //means we have more than one pad
490 local->fLastMergedPad = pad;
492 currentPt[ncurrent] = local;
496 } //Checking for match at previous pad
497 } //Loop over results on previous pad.
499 if(newcluster && ncurrent<kPadArraySize){
500 //Start a new cluster. Add it to the clusterlist, and update
501 //the list of pointers to clusters in current pad.
502 //current pad will be previous pad on next pad.
504 //Add to the clusterlist:
505 AliClusterData *tmp = &clusterlist[ntotal];
506 tmp->fTotalCharge = seqcharge;
508 tmp->fPad2 = paderror;
509 tmp->fTime = seqaverage;
510 tmp->fTime2 = seqerror;
511 tmp->fMean = seqmean;
512 tmp->fFlags = 0; //flags for single pad clusters
513 tmp->fLastMergedPad = pad;
516 tmp->fChargeFalling = 0;
517 tmp->fLastCharge = seqcharge;
520 //Update list of pointers to previous pad:
521 currentPt[ncurrent] = &clusterlist[ntotal];
527 if(newbin >= 0) goto redo;
529 // to prevent endless loop
530 if(time >= AliHLTTPCTransform::GetNTimeBins()){
531 HLTWarning("Timebin (%d) out of range (%d)", time, AliHLTTPCTransform::GetNTimeBins());
536 if(!readValue) break; //No more value
538 if (ntotal>=kClusterListSize || ncurrent>=kPadArraySize) {
539 HLTWarning("pad array size exceeded ntotal=%d ncurrent=%d, skip rest of the data", ntotal, ncurrent);
543 if(fCurrentRow != newRow){
544 WriteClusters(ntotal,clusterlist);
554 fCurrentRow = newRow;
560 } // END while(readValue)
562 WriteClusters(ntotal,clusterlist);
564 HLTInfo("ClusterFinder found %d clusters in slice %d patch %d", fNClusters, fCurrentSlice, fCurrentPatch);
568 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliClusterData *list)
570 //write cluster to output pointer
571 Int_t thisrow,thissector;
572 UInt_t counter = fNClusters;
574 for(int j=0; j<nclusters; j++)
576 if(!list[j].fFlags) continue; //discard single pad clusters
577 if(list[j].fTotalCharge < fThreshold) continue; //noise cluster
580 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
581 Float_t fpad2=fXYErr*fXYErr; //fixed given error
582 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
583 Float_t ftime2=fZErr*fZErr; //fixed given error
590 if(fCalcerr) { //calc the errors, otherwice take the fixed error
591 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
592 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
593 Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
596 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
597 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
601 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
603 fpad2*=0.108; //constants are from offline studies
607 } else fpad2=sy2; //take the width not the error
609 Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
612 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
613 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
617 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
619 ftime2 *= 0.169; //constants are from offline studies
623 } else ftime2=sz2; //take the width, not the error
627 cout<<"WriteCluster: padrow "<<fCurrentRow<<" pad "<<fpad << " +- "<<fpad2<<" time "<<ftime<<" +- "<<ftime2<<" charge "<<list[j].fTotalCharge<<endl;
630 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
631 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
633 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
634 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
635 if(fNClusters >= fMaxNClusters)
637 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
638 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
642 fSpacePointData[counter].fX = xyz[0];
643 fSpacePointData[counter].fY = xyz[1];
644 fSpacePointData[counter].fZ = xyz[2];
647 fSpacePointData[counter].fX = fCurrentRow;
648 fSpacePointData[counter].fY = fpad;
649 fSpacePointData[counter].fZ = ftime;
652 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
653 fSpacePointData[counter].fPadRow = fCurrentRow;
654 fSpacePointData[counter].fSigmaY2 = fpad2;
655 fSpacePointData[counter].fSigmaZ2 = ftime2;
657 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
658 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
660 Int_t patch=fCurrentPatch;
661 if(patch==-1) patch=0; //never store negative patch number
662 fSpacePointData[counter].fID = counter
663 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
667 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
669 fSpacePointData[counter].fTrackID[0] = trackID[0];
670 fSpacePointData[counter].fTrackID[1] = trackID[1];
671 fSpacePointData[counter].fTrackID[2] = trackID[2];
673 //cout<<"padrow "<<fCurrentRow<<" pad "<<(Int_t)rint(fpad)<<" time "<<(Int_t)rint(ftime)<<" Trackid "<<trackID[0]<<endl;
681 // STILL TO FIX ----------------------------------------------------------------------------
684 void AliHLTTPCClusterFinder::GetTrackID(Int_t pad,Int_t time,Int_t *trackID)
687 AliHLTTPCDigitRowData *rowPt = (AliHLTTPCDigitRowData*)fDigitRowData;
689 trackID[0]=trackID[1]=trackID[2]=-2;
690 //cout<<"Looking for pad "<<pad<<" time "<<time<<endl;
691 for(Int_t i=fFirstRow; i<=fLastRow; i++){
692 if(rowPt->fRow < (UInt_t)fCurrentRow){
693 AliHLTTPCMemHandler::UpdateRowPointer(rowPt);
696 AliHLTTPCDigitData *digPt = (AliHLTTPCDigitData*)rowPt->fDigitData;
697 for(UInt_t j=0; j<rowPt->fNDigit; j++){
698 Int_t cpad = digPt[j].fPad;
699 Int_t ctime = digPt[j].fTime;
700 if(cpad != pad) continue;
701 if(ctime != time) continue;
703 trackID[0] = digPt[j].fTrackID[0];
704 trackID[1] = digPt[j].fTrackID[1];
705 trackID[2] = digPt[j].fTrackID[2];
707 //cout<<"Reading row "<<fCurrentRow<<" pad "<<cpad<<" time "<<ctime<<" trackID "<<digPt[j].fTrackID[0]<<endl;