2 // Original: AliL3ClustFinderNew.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 //_____________________________________________________________
46 // AliHLTTPCClusterFinder
48 // The current cluster finder for HLT
51 // The cluster finder is initialized with the Init function,
52 // providing the slice and patch information to work on.
54 // The input is a provided by the AliHLTTPCDigitReader class,
55 // using the init() funktion, and the next() funktion in order
56 // to get the next bin. Either packed or unpacked data can be
57 // processed, dependent if one uses AliHLTTPCDigitReaderPacked
58 // class or AliHLTTPCDigitReaderUnpacked class in the
59 // Clusterfinder Component.
60 // The resulting space points will be in the
61 // array given by the SetOutputArray function.
63 // There are several setters which control the behaviour:
65 // - SetXYError(Float_t): set fixed error in XY direction
66 // - SetZError(Float_t): set fixed error in Z direction
67 // (used if errors are not calculated)
68 // - SetDeconv(Bool_t): switch on/off deconvolution
69 // - SetThreshold(UInt_t): set charge threshold for cluster
70 // - SetMatchWidth(UInt_t): set the match distance in
71 // time for sequences to be merged
72 // - SetSTDOutput(Bool_t): switch on/off output about found clusters
73 // - SetCalcErr(Bool_t): switch on/off calculation of
74 // space point errors (or widths in raw system)
75 // - SetRawSP(Bool_t): switch on/off convertion to raw system
80 // AliHLTTPCFileHandler *file = new AliHLTTPCFileHandler();
81 // file->SetAliInput(digitfile); //give some input file
82 // for(int slice=0; slice<=35; slice++){
83 // for(int patch=0; pat<6; pat++){
84 // file->Init(slice,patch);
86 // UInt_t maxclusters=100000;
87 // UInt_t pointsize = maxclusters*sizeof(AliHLTTPCSpacePointData);
88 // AliHLTTPCSpacePointData *points = (AliHLTTPCSpacePointData*)memory->Allocate(pointsize);
89 // AliHLTTPCDigitRowData *digits = (AliHLTTPCDigitRowData*)file->AliAltroDigits2Memory(ndigits,event);
90 // AliHLTTPCClusterFinder *cf = new AliHLTTPCClusterFinder();
91 // cf->SetMatchWidth(2);
92 // cf->InitSlice( slice, patch, row[0], row[1], maxPoints );
93 // cf->SetSTDOutput(kTRUE); //Some output to standard IO
94 // cf->SetRawSP(kFALSE); //Convert space points to local system
95 // cf->SetThreshold(5); //Threshold of cluster charge
96 // cf->SetDeconv(kTRUE); //Deconv in pad and time direction
97 // cf->SetCalcErr(kTRUE); //Calculate the errors of the spacepoints
98 // cf->SetOutputArray(points); //Move the spacepoints to the array
99 // cf->Read(iter->fPtr, iter->fSize ); //give the data to the cf
100 // cf->ProcessDigits(); //process the rows given by init
101 // Int_t npoints = cf->GetNumberOfClusters();
102 // AliHLTTPCMemHandler *out= new AliHLTTPCMemHandler();
103 // out->SetBinaryOutput(fname);
104 // out->Memory2Binary(npoints,points); //store the spacepoints
105 // out->CloseBinaryOutput();
114 ClassImp(AliHLTTPCClusterFinder)
116 AliHLTTPCClusterFinder::AliHLTTPCClusterFinder()
120 fSignalThreshold(-1),
121 fOccupancyLimit(1.0),
136 AliHLTTPCClusterFinder::AliHLTTPCClusterFinder(const AliHLTTPCClusterFinder& src)
139 fThreshold(src.fThreshold),
140 fSignalThreshold(src.fSignalThreshold),
141 fOccupancyLimit(src.fOccupancyLimit),
144 fDeconvPad(src.fDeconvPad),
145 fDeconvTime(src.fDeconvTime),
146 fStdout(src.fStdout),
147 fCalcerr(src.fCalcerr),
149 fFirstRow(src.fFirstRow),
150 fLastRow(src.fLastRow),
151 fDigitReader(src.fDigitReader)
155 AliHLTTPCClusterFinder& AliHLTTPCClusterFinder::operator=(const AliHLTTPCClusterFinder& src)
158 fThreshold=src.fThreshold;
159 fSignalThreshold=src.fSignalThreshold;
160 fOccupancyLimit=src.fOccupancyLimit;
163 fDeconvPad=src.fDeconvPad;
164 fDeconvTime=src.fDeconvTime;
166 fCalcerr=src.fCalcerr;
168 fFirstRow=src.fFirstRow;
169 fLastRow=src.fLastRow;
170 fDigitReader=src.fDigitReader;
174 AliHLTTPCClusterFinder::~AliHLTTPCClusterFinder()
179 void AliHLTTPCClusterFinder::InitSlice(Int_t slice,Int_t patch,Int_t firstrow, Int_t lastrow,Int_t nmaxpoints)
183 fMaxNClusters = nmaxpoints;
184 fCurrentSlice = slice;
185 fCurrentPatch = patch;
186 fFirstRow = firstrow;
190 void AliHLTTPCClusterFinder::InitSlice(Int_t slice,Int_t patch,Int_t nmaxpoints)
194 fMaxNClusters = nmaxpoints;
195 fCurrentSlice = slice;
196 fCurrentPatch = patch;
197 fFirstRow=AliHLTTPCTransform::GetFirstRow(patch);
198 fLastRow=AliHLTTPCTransform::GetLastRow(patch);
201 void AliHLTTPCClusterFinder::SetOutputArray(AliHLTTPCSpacePointData *pt)
203 //set pointer to output
204 fSpacePointData = pt;
207 void AliHLTTPCClusterFinder::Read(void* ptr,unsigned long size){
209 fPtr = (UChar_t*)ptr;
213 void AliHLTTPCClusterFinder::ProcessDigits()
215 bool readValue = true;
218 UShort_t time=0,newTime=0;
219 UInt_t pad=0,newPad=0;
220 AliHLTTPCSignal_t charge=0;
224 // initialize block for reading packed data
225 fDigitReader->InitBlock(fPtr,fSize,fFirstRow,fLastRow,fCurrentPatch,fCurrentSlice);
226 readValue = fDigitReader->Next();
228 // Matthias 08.11.2006 the following return would cause termination without writing the
229 // ClusterData and thus would block the component. I just wnt to have the commented line
230 // here for information
231 //if (!readValue)return;
233 pad = fDigitReader->GetPad();
234 time = fDigitReader->GetTime();
235 fCurrentRow = fDigitReader->GetRow();
237 if ( fCurrentPatch >= 2 ) // Outer sector, patches 2, 3, 4, 5
238 rowOffset = AliHLTTPCTransform::GetFirstRow( 2 );
240 fCurrentRow += rowOffset;
242 UInt_t lastpad = 123456789;
243 const Int_t kPadArraySize=5000;
244 const Int_t kClusterListSize=10000;
245 AliClusterData *pad1[kPadArraySize]; //2 lists for internal memory=2pads
246 AliClusterData *pad2[kPadArraySize]; //2 lists for internal memory=2pads
247 AliClusterData clusterlist[kClusterListSize]; //Clusterlist
249 AliClusterData **currentPt; //List of pointers to the current pad
250 AliClusterData **previousPt; //List of pointers to the previous pad
253 UInt_t nprevious=0,ncurrent=0,ntotal=0;
255 /* quick implementation of baseline calculation and zero suppression
256 open a pad object for each pad and delete it after processing.
257 later a list of pad objects with base line history can be used
258 The whole thing only works if we really get unprocessed raw data, if
259 the data is already zero suppressed, there might be gaps in the time
262 Int_t gatingGridOffset=50;
263 AliHLTTPCPad baseline(gatingGridOffset, AliHLTTPCTransform::GetNTimeBins());
264 // just to make later conversion to a list of objects easier
265 AliHLTTPCPad* pCurrentPad=NULL;
266 if (fSignalThreshold>=0) {
267 pCurrentPad=&baseline;
268 baseline.SetThreshold(fSignalThreshold);
271 while ( readValue ){ // Reads through all digits in block
277 if(currentPt == pad2){
285 nprevious = ncurrent;
287 if(pad != lastpad+1){
288 //this happens if there is a pad with no signal.
289 nprevious = ncurrent = 0;
294 Bool_t newcluster = kTRUE;
295 UInt_t seqcharge=0,seqaverage=0,seqerror=0;
296 UInt_t lastcharge=0,lastwas_falling=0;
301 redo: //This is a goto.
312 while(1){ //Loop over time bins of current pad
313 // read all the values for one pad at once to calculate the base line
315 if (!pCurrentPad->IsStarted()) {
316 //HLTDebug("reading data for pad %d, padrow %d", fDigitReader->GetPad(), fDigitReader->GetRow()+rowOffset);
317 pCurrentPad->SetID(fDigitReader->GetRow()+rowOffset,fDigitReader->GetPad());
318 if ((pCurrentPad->StartEvent())>=0) {
320 if ((fDigitReader->GetRow()+rowOffset)!=pCurrentPad->GetRowNumber()) break;
321 if (fDigitReader->GetPad()!=pCurrentPad->GetPadNumber()) break;
322 pCurrentPad->SetRawData(fDigitReader->GetTime(), fDigitReader->GetSignal());
323 //HLTDebug("set raw data to pad: bin %d charge %d", fDigitReader->GetTime(), fDigitReader->GetSignal());
324 } while ((readValue = fDigitReader->Next())!=0);
326 pCurrentPad->CalculateBaseLine(AliHLTTPCTransform::GetNTimeBins()/2);
327 if (pCurrentPad->Next(kTRUE/*do zero suppression*/)==0) {
328 //HLTDebug("no data available after zero suppression");
329 pCurrentPad->StopEvent();
330 pCurrentPad->ResetHistory();
333 time=pCurrentPad->GetCurrentPosition();
334 if (time>pCurrentPad->GetSize()) {
335 HLTError("invalid time bin for pad");
342 Float_t occupancy=pCurrentPad->GetOccupancy();
343 //HLTDebug("pad %d occupancy level: %f", pCurrentPad->GetPadNumber(), occupancy);
344 if ( occupancy < fOccupancyLimit ) {
345 charge = pCurrentPad->GetCorrectedData();
348 //HLTDebug("ignoring pad %d with occupancy level %f", pCurrentPad->GetPadNumber(), occupancy);
351 charge = fDigitReader->GetSignal();
353 //HLTDebug("get next charge value: position %d charge %d", time, charge);
357 if (fDigitReader->GetRow() == 90){
358 ///// LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::Row","row90") << "PAD=" << fDigitReader->GetPad() << " TIME=" << fDigitReader->GetTime()
359 // << " SIGNAL=" << fDigitReader->GetSignal() << ENDLOG;
363 if(time >= AliHLTTPCTransform::GetNTimeBins()){
364 HLTWarning("Timebin (%d) out of range (%d)", time, AliHLTTPCTransform::GetNTimeBins());
369 //Get the current ADC-value
372 //Check if the last pixel in the sequence is smaller than this
373 if(charge > lastcharge){
379 else lastwas_falling = 1; //last pixel was larger than this
383 //Sum the total charge of this sequence
385 seqaverage += time*charge;
386 seqerror += time*time*charge;
390 if((pCurrentPad->Next(kTRUE/*do zero suppression*/))==0) {
391 pCurrentPad->StopEvent();
392 pCurrentPad->ResetHistory();
394 newPad = fDigitReader->GetPad();
395 newTime = fDigitReader->GetTime();
396 newRow = fDigitReader->GetRow() + rowOffset;
401 newPad=pCurrentPad->GetPadNumber();
402 newTime=pCurrentPad->GetCurrentPosition();
403 newRow=pCurrentPad->GetRowNumber();
405 readValue = fDigitReader->Next();
406 //Check where to stop:
407 if(!readValue) break; //No more value
409 newPad = fDigitReader->GetPad();
410 newTime = fDigitReader->GetTime();
411 newRow = fDigitReader->GetRow() + rowOffset;
414 if(newPad != pad)break; //new pad
415 if(newTime != time+1) break; //end of sequence
417 // pad = newpad; is equal
420 }//end loop over sequence
422 //HLTDebug("ended time bin sequence loop: seqcharge=%d readValue=%d", seqcharge, readValue);
423 //HLTDebug("pad=%d newpad=%d current row=%d newrow=%d", pad, newPad, fCurrentRow, newRow);
425 // with active zero suppression zero values are possible
429 //Calculate mean of sequence:
432 seqmean = seqaverage/seqcharge;
434 LOG(AliHLTTPCLog::kFatal,"AliHLTTPCClusterFinder::ProcessRow","Data")
435 <<"Error in data given to the cluster finder"<<ENDLOG;
440 //Calculate mean in pad direction:
441 Int_t padmean = seqcharge*pad;
442 Int_t paderror = pad*padmean;
445 //Compare with results on previous pad:
446 for(UInt_t p=0; p<nprevious && p<kPadArraySize && ncurrent<kPadArraySize; p++){
448 //dont merge sequences on the same pad twice
449 if(previousPt[p]->fLastMergedPad==pad) continue;
451 Int_t difference = seqmean - previousPt[p]->fMean;
452 if(difference < -fMatch) break;
454 if(difference <= fMatch){ //There is a match here!!
455 AliClusterData *local = previousPt[p];
458 if(seqcharge > local->fLastCharge){
459 if(local->fChargeFalling){ //The previous pad was falling
460 break; //create a new cluster
463 else local->fChargeFalling = 1;
464 local->fLastCharge = seqcharge;
467 //Don't create a new cluster, because we found a match
470 //Update cluster on current pad with the matching one:
471 local->fTotalCharge += seqcharge;
472 local->fPad += padmean;
473 local->fPad2 += paderror;
474 local->fTime += seqaverage;
475 local->fTime2 += seqerror;
476 local->fMean = seqmean;
477 local->fFlags++; //means we have more than one pad
478 local->fLastMergedPad = pad;
480 currentPt[ncurrent] = local;
484 } //Checking for match at previous pad
485 } //Loop over results on previous pad.
488 if(newcluster && ncurrent<kPadArraySize){
489 //Start a new cluster. Add it to the clusterlist, and update
490 //the list of pointers to clusters in current pad.
491 //current pad will be previous pad on next pad.
493 //Add to the clusterlist:
494 AliClusterData *tmp = &clusterlist[ntotal];
495 tmp->fTotalCharge = seqcharge;
497 tmp->fPad2 = paderror;
498 tmp->fTime = seqaverage;
499 tmp->fTime2 = seqerror;
500 tmp->fMean = seqmean;
501 tmp->fFlags = 0; //flags for single pad clusters
502 tmp->fLastMergedPad = pad;
505 tmp->fChargeFalling = 0;
506 tmp->fLastCharge = seqcharge;
509 //Update list of pointers to previous pad:
510 currentPt[ncurrent] = &clusterlist[ntotal];
516 if(newbin >= 0) goto redo;
518 // to prevent endless loop
519 if(time >= AliHLTTPCTransform::GetNTimeBins()){
520 HLTWarning("Timebin (%d) out of range (%d)", time, AliHLTTPCTransform::GetNTimeBins());
525 if(!readValue) break; //No more value
527 if (ntotal>=kClusterListSize || ncurrent>=kPadArraySize) {
528 HLTWarning("pad array size exceeded ntotal=%d ncurrent=%d, skip rest of the data", ntotal, ncurrent);
532 if(fCurrentRow != newRow){
533 WriteClusters(ntotal,clusterlist);
543 fCurrentRow = newRow;
549 } // END while(readValue)
551 WriteClusters(ntotal,clusterlist);
553 HLTInfo("ClusterFinder found %d clusters in slice %d patch %d", fNClusters, fCurrentSlice, fCurrentPatch);
557 void AliHLTTPCClusterFinder::WriteClusters(Int_t nclusters,AliClusterData *list)
559 //write cluster to output pointer
560 Int_t thisrow,thissector;
561 UInt_t counter = fNClusters;
563 for(int j=0; j<nclusters; j++)
565 if(!list[j].fFlags) continue; //discard single pad clusters
566 if(list[j].fTotalCharge < fThreshold) continue; //noise cluster
569 Float_t fpad =(Float_t)list[j].fPad / list[j].fTotalCharge;
570 Float_t fpad2=fXYErr*fXYErr; //fixed given error
571 Float_t ftime =(Float_t)list[j].fTime / list[j].fTotalCharge;
572 Float_t ftime2=fZErr*fZErr; //fixed given error
579 if(fCalcerr) { //calc the errors, otherwice take the fixed error
580 Int_t patch = AliHLTTPCTransform::GetPatch(fCurrentRow);
581 UInt_t q2=list[j].fTotalCharge*list[j].fTotalCharge;
582 Float_t sy2=list[j].fPad2 * list[j].fTotalCharge - list[j].fPad * list[j].fPad;
585 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
586 <<"SigmaY2 negative "<<sy2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
590 fpad2 = (sy2 + 1./12)*AliHLTTPCTransform::GetPadPitchWidth(patch)*AliHLTTPCTransform::GetPadPitchWidth(patch);
592 fpad2*=0.108; //constants are from offline studies
596 } else fpad2=sy2; //take the width not the error
598 Float_t sz2=list[j].fTime2*list[j].fTotalCharge - list[j].fTime*list[j].fTime;
601 LOG(AliHLTTPCLog::kError,"AliHLTTPCClusterFinder::WriteClusters","Cluster width")
602 <<"SigmaZ2 negative "<<sz2<<" on row "<<fCurrentRow<<" "<<fpad<<" "<<ftime<<ENDLOG;
606 ftime2 = (sz2 + 1./12)*AliHLTTPCTransform::GetZWidth()*AliHLTTPCTransform::GetZWidth();
608 ftime2 *= 0.169; //constants are from offline studies
612 } else ftime2=sz2; //take the width, not the error
616 cout<<"WriteCluster: padrow "<<fCurrentRow<<" pad "<<fpad << " +- "<<fpad2<<" time "<<ftime<<" +- "<<ftime2<<" charge "<<list[j].fTotalCharge<<endl;
619 AliHLTTPCTransform::Slice2Sector(fCurrentSlice,fCurrentRow,thissector,thisrow);
620 AliHLTTPCTransform::Raw2Local(xyz,thissector,thisrow,fpad,ftime);
622 if(xyz[0]==0) LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder","Cluster Finder")
623 <<AliHLTTPCLog::kDec<<"Zero cluster"<<ENDLOG;
624 if(fNClusters >= fMaxNClusters)
626 LOG(AliHLTTPCLog::kError,"AliHLTTPCClustFinder::WriteClusters","Cluster Finder")
627 <<AliHLTTPCLog::kDec<<"Too many clusters "<<fNClusters<<ENDLOG;
631 fSpacePointData[counter].fX = xyz[0];
632 fSpacePointData[counter].fY = xyz[1];
633 fSpacePointData[counter].fZ = xyz[2];
636 fSpacePointData[counter].fX = fCurrentRow;
637 fSpacePointData[counter].fY = fpad;
638 fSpacePointData[counter].fZ = ftime;
641 fSpacePointData[counter].fCharge = list[j].fTotalCharge;
642 fSpacePointData[counter].fPadRow = fCurrentRow;
643 fSpacePointData[counter].fSigmaY2 = fpad2;
644 fSpacePointData[counter].fSigmaZ2 = ftime2;
646 fSpacePointData[counter].fUsed = kFALSE; // only used / set in AliHLTTPCDisplay
647 fSpacePointData[counter].fTrackN = -1; // only used / set in AliHLTTPCDisplay
649 Int_t patch=fCurrentPatch;
650 if(patch==-1) patch=0; //never store negative patch number
651 fSpacePointData[counter].fID = counter
652 +((fCurrentSlice&0x7f)<<25)+((patch&0x7)<<22);//Uli
656 GetTrackID((Int_t)rint(fpad),(Int_t)rint(ftime),trackID);
658 fSpacePointData[counter].fTrackID[0] = trackID[0];
659 fSpacePointData[counter].fTrackID[1] = trackID[1];
660 fSpacePointData[counter].fTrackID[2] = trackID[2];
662 //cout<<"padrow "<<fCurrentRow<<" pad "<<(Int_t)rint(fpad)<<" time "<<(Int_t)rint(ftime)<<" Trackid "<<trackID[0]<<endl;
670 // STILL TO FIX ----------------------------------------------------------------------------
673 void AliHLTTPCClusterFinder::GetTrackID(Int_t pad,Int_t time,Int_t *trackID)
676 AliHLTTPCDigitRowData *rowPt = (AliHLTTPCDigitRowData*)fDigitRowData;
678 trackID[0]=trackID[1]=trackID[2]=-2;
679 //cout<<"Looking for pad "<<pad<<" time "<<time<<endl;
680 for(Int_t i=fFirstRow; i<=fLastRow; i++){
681 if(rowPt->fRow < (UInt_t)fCurrentRow){
682 AliHLTTPCMemHandler::UpdateRowPointer(rowPt);
685 AliHLTTPCDigitData *digPt = (AliHLTTPCDigitData*)rowPt->fDigitData;
686 for(UInt_t j=0; j<rowPt->fNDigit; j++){
687 Int_t cpad = digPt[j].fPad;
688 Int_t ctime = digPt[j].fTime;
689 if(cpad != pad) continue;
690 if(ctime != time) continue;
692 trackID[0] = digPt[j].fTrackID[0];
693 trackID[1] = digPt[j].fTrackID[1];
694 trackID[2] = digPt[j].fTrackID[2];
696 //cout<<"Reading row "<<fCurrentRow<<" pad "<<cpad<<" time "<<ctime<<" trackID "<<digPt[j].fTrackID[0]<<endl;